Store remote domain in Cloud preferences (#64532)

This commit is contained in:
Erik Montnemery 2022-01-21 18:42:34 +01:00 committed by GitHub
parent 9f12612391
commit 3575009330
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 88 additions and 11 deletions

View File

@ -157,10 +157,10 @@ def async_remote_ui_url(hass: HomeAssistant) -> str:
if not hass.data[DOMAIN].client.prefs.remote_enabled: if not hass.data[DOMAIN].client.prefs.remote_enabled:
raise CloudNotAvailable raise CloudNotAvailable
if not hass.data[DOMAIN].remote.instance_domain: if not (remote_domain := hass.data[DOMAIN].client.prefs.remote_domain):
raise CloudNotAvailable raise CloudNotAvailable
return f"https://{hass.data[DOMAIN].remote.instance_domain}" return f"https://{remote_domain}"
def is_cloudhook_request(request): def is_cloudhook_request(request):
@ -235,7 +235,12 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
Platform.TTS, DOMAIN, {}, config Platform.TTS, DOMAIN, {}, config
) )
async def _on_initialized():
"""Update preferences."""
await prefs.async_update(remote_domain=cloud.remote.instance_domain)
cloud.iot.register_on_connect(_on_connect) cloud.iot.register_on_connect(_on_connect)
cloud.register_on_initialized(_on_initialized)
await cloud.initialize() await cloud.initialize()
await http_api.async_setup(hass) await http_api.async_setup(hass)

View File

@ -18,6 +18,7 @@ PREF_ALIASES = "aliases"
PREF_SHOULD_EXPOSE = "should_expose" PREF_SHOULD_EXPOSE = "should_expose"
PREF_GOOGLE_LOCAL_WEBHOOK_ID = "google_local_webhook_id" PREF_GOOGLE_LOCAL_WEBHOOK_ID = "google_local_webhook_id"
PREF_USERNAME = "username" PREF_USERNAME = "username"
PREF_REMOTE_DOMAIN = "remote_domain"
PREF_ALEXA_DEFAULT_EXPOSE = "alexa_default_expose" PREF_ALEXA_DEFAULT_EXPOSE = "alexa_default_expose"
PREF_GOOGLE_DEFAULT_EXPOSE = "google_default_expose" PREF_GOOGLE_DEFAULT_EXPOSE = "google_default_expose"
PREF_TTS_DEFAULT_VOICE = "tts_default_voice" PREF_TTS_DEFAULT_VOICE = "tts_default_voice"

View File

@ -2,7 +2,7 @@
"domain": "cloud", "domain": "cloud",
"name": "Home Assistant Cloud", "name": "Home Assistant Cloud",
"documentation": "https://www.home-assistant.io/integrations/cloud", "documentation": "https://www.home-assistant.io/integrations/cloud",
"requirements": ["hass-nabucasa==0.51.0"], "requirements": ["hass-nabucasa==0.52.0"],
"dependencies": ["http", "webhook"], "dependencies": ["http", "webhook"],
"after_dependencies": ["google_assistant", "alexa"], "after_dependencies": ["google_assistant", "alexa"],
"codeowners": ["@home-assistant/cloud"], "codeowners": ["@home-assistant/cloud"],

View File

@ -30,6 +30,7 @@ from .const import (
PREF_GOOGLE_REPORT_STATE, PREF_GOOGLE_REPORT_STATE,
PREF_GOOGLE_SECURE_DEVICES_PIN, PREF_GOOGLE_SECURE_DEVICES_PIN,
PREF_OVERRIDE_NAME, PREF_OVERRIDE_NAME,
PREF_REMOTE_DOMAIN,
PREF_SHOULD_EXPOSE, PREF_SHOULD_EXPOSE,
PREF_TTS_DEFAULT_VOICE, PREF_TTS_DEFAULT_VOICE,
PREF_USERNAME, PREF_USERNAME,
@ -85,6 +86,7 @@ class CloudPreferences:
alexa_default_expose=UNDEFINED, alexa_default_expose=UNDEFINED,
google_default_expose=UNDEFINED, google_default_expose=UNDEFINED,
tts_default_voice=UNDEFINED, tts_default_voice=UNDEFINED,
remote_domain=UNDEFINED,
): ):
"""Update user preferences.""" """Update user preferences."""
prefs = {**self._prefs} prefs = {**self._prefs}
@ -103,6 +105,7 @@ class CloudPreferences:
(PREF_ALEXA_DEFAULT_EXPOSE, alexa_default_expose), (PREF_ALEXA_DEFAULT_EXPOSE, alexa_default_expose),
(PREF_GOOGLE_DEFAULT_EXPOSE, google_default_expose), (PREF_GOOGLE_DEFAULT_EXPOSE, google_default_expose),
(PREF_TTS_DEFAULT_VOICE, tts_default_voice), (PREF_TTS_DEFAULT_VOICE, tts_default_voice),
(PREF_REMOTE_DOMAIN, remote_domain),
): ):
if value is not UNDEFINED: if value is not UNDEFINED:
prefs[key] = value prefs[key] = value
@ -208,6 +211,11 @@ class CloudPreferences:
return True return True
@property
def remote_domain(self):
"""Return remote domain."""
return self._prefs.get(PREF_REMOTE_DOMAIN)
@property @property
def alexa_enabled(self): def alexa_enabled(self):
"""Return if Alexa is enabled.""" """Return if Alexa is enabled."""
@ -321,5 +329,6 @@ class CloudPreferences:
PREF_GOOGLE_ENTITY_CONFIGS: {}, PREF_GOOGLE_ENTITY_CONFIGS: {},
PREF_GOOGLE_LOCAL_WEBHOOK_ID: webhook.async_generate_id(), PREF_GOOGLE_LOCAL_WEBHOOK_ID: webhook.async_generate_id(),
PREF_GOOGLE_SECURE_DEVICES_PIN: None, PREF_GOOGLE_SECURE_DEVICES_PIN: None,
PREF_REMOTE_DOMAIN: None,
PREF_USERNAME: username, PREF_USERNAME: username,
} }

View File

@ -84,6 +84,8 @@ async def websocket_get_entity(hass, connection, msg):
vol.Coerce(RegistryEntryDisabler), RegistryEntryDisabler.USER.value vol.Coerce(RegistryEntryDisabler), RegistryEntryDisabler.USER.value
), ),
), ),
vol.Inclusive("options_domain", "entity_option"): str,
vol.Inclusive("options", "entity_option"): vol.Any(None, dict),
} }
) )
async def websocket_update_entity(hass, connection, msg): async def websocket_update_entity(hass, connection, msg):
@ -93,7 +95,8 @@ async def websocket_update_entity(hass, connection, msg):
""" """
registry = await async_get_registry(hass) registry = await async_get_registry(hass)
if msg["entity_id"] not in registry.entities: entity_id = msg["entity_id"]
if entity_id not in registry.entities:
connection.send_message( connection.send_message(
websocket_api.error_message(msg["id"], ERR_NOT_FOUND, "Entity not found") websocket_api.error_message(msg["id"], ERR_NOT_FOUND, "Entity not found")
) )
@ -105,7 +108,7 @@ async def websocket_update_entity(hass, connection, msg):
if key in msg: if key in msg:
changes[key] = msg[key] changes[key] = msg[key]
if "new_entity_id" in msg and msg["new_entity_id"] != msg["entity_id"]: if "new_entity_id" in msg and msg["new_entity_id"] != entity_id:
changes["new_entity_id"] = msg["new_entity_id"] changes["new_entity_id"] = msg["new_entity_id"]
if hass.states.get(msg["new_entity_id"]) is not None: if hass.states.get(msg["new_entity_id"]) is not None:
connection.send_message( connection.send_message(
@ -118,7 +121,7 @@ async def websocket_update_entity(hass, connection, msg):
return return
if "disabled_by" in msg and msg["disabled_by"] is None: if "disabled_by" in msg and msg["disabled_by"] is None:
entity = registry.entities[msg["entity_id"]] entity = registry.entities[entity_id]
if entity.device_id: if entity.device_id:
device_registry = await hass.helpers.device_registry.async_get_registry() device_registry = await hass.helpers.device_registry.async_get_registry()
device = device_registry.async_get(entity.device_id) device = device_registry.async_get(entity.device_id)
@ -132,12 +135,28 @@ async def websocket_update_entity(hass, connection, msg):
try: try:
if changes: if changes:
entry = registry.async_update_entity(msg["entity_id"], **changes) registry.async_update_entity(entity_id, **changes)
except ValueError as err: except ValueError as err:
connection.send_message( connection.send_message(
websocket_api.error_message(msg["id"], "invalid_info", str(err)) websocket_api.error_message(msg["id"], "invalid_info", str(err))
) )
return return
if "new_entity_id" in msg:
entity_id = msg["new_entity_id"]
try:
if "options_domain" in msg:
registry.async_update_entity_options(
entity_id, msg["options_domain"], msg["options"]
)
except ValueError as err:
connection.send_message(
websocket_api.error_message(msg["id"], "invalid_info", str(err))
)
return
entry = registry.async_get(entity_id)
result = {"entity_entry": _entry_ext_dict(entry)} result = {"entity_entry": _entry_ext_dict(entry)}
if "disabled_by" in changes and changes["disabled_by"] is None: if "disabled_by" in changes and changes["disabled_by"] is None:
config_entry = hass.config_entries.async_get_entry(entry.config_entry_id) config_entry = hass.config_entries.async_get_entry(entry.config_entry_id)
@ -195,6 +214,7 @@ def _entry_ext_dict(entry):
data = _entry_dict(entry) data = _entry_dict(entry)
data["capabilities"] = entry.capabilities data["capabilities"] = entry.capabilities
data["device_class"] = entry.device_class data["device_class"] = entry.device_class
data["options"] = entry.options
data["original_device_class"] = entry.original_device_class data["original_device_class"] = entry.original_device_class
data["original_icon"] = entry.original_icon data["original_icon"] = entry.original_icon
data["original_name"] = entry.original_name data["original_name"] = entry.original_name

View File

@ -15,7 +15,7 @@ certifi>=2021.5.30
ciso8601==2.2.0 ciso8601==2.2.0
cryptography==35.0.0 cryptography==35.0.0
emoji==1.5.0 emoji==1.5.0
hass-nabucasa==0.51.0 hass-nabucasa==0.52.0
home-assistant-frontend==20220118.0 home-assistant-frontend==20220118.0
httpx==0.21.0 httpx==0.21.0
ifaddr==0.1.7 ifaddr==0.1.7

View File

@ -809,7 +809,7 @@ habitipy==0.2.0
hangups==0.4.17 hangups==0.4.17
# homeassistant.components.cloud # homeassistant.components.cloud
hass-nabucasa==0.51.0 hass-nabucasa==0.52.0
# homeassistant.components.splunk # homeassistant.components.splunk
hass_splunk==0.1.1 hass_splunk==0.1.1

View File

@ -522,7 +522,7 @@ habitipy==0.2.0
hangups==0.4.17 hangups==0.4.17
# homeassistant.components.cloud # homeassistant.components.cloud
hass-nabucasa==0.51.0 hass-nabucasa==0.52.0
# homeassistant.components.tasmota # homeassistant.components.tasmota
hatasmota==0.3.1 hatasmota==0.3.1

View File

@ -171,6 +171,7 @@ async def test_remote_ui_url(hass, mock_cloud_fixture):
with pytest.raises(cloud.CloudNotAvailable): with pytest.raises(cloud.CloudNotAvailable):
cloud.async_remote_ui_url(hass) cloud.async_remote_ui_url(hass)
cl.remote._instance_domain = "example.com" # Remote finished initializing
cl.client.prefs._prefs["remote_domain"] = "example.com"
assert cloud.async_remote_ui_url(hass) == "https://example.com" assert cloud.async_remote_ui_url(hass) == "https://example.com"

View File

@ -111,6 +111,7 @@ async def test_get_entity(hass, client):
"entity_id": "test_domain.name", "entity_id": "test_domain.name",
"icon": None, "icon": None,
"name": "Hello World", "name": "Hello World",
"options": {},
"original_device_class": None, "original_device_class": None,
"original_icon": None, "original_icon": None,
"original_name": None, "original_name": None,
@ -138,6 +139,7 @@ async def test_get_entity(hass, client):
"entity_id": "test_domain.no_name", "entity_id": "test_domain.no_name",
"icon": None, "icon": None,
"name": None, "name": None,
"options": {},
"original_device_class": None, "original_device_class": None,
"original_icon": None, "original_icon": None,
"original_name": None, "original_name": None,
@ -197,6 +199,7 @@ async def test_update_entity(hass, client):
"entity_id": "test_domain.world", "entity_id": "test_domain.world",
"icon": "icon:after update", "icon": "icon:after update",
"name": "after update", "name": "after update",
"options": {},
"original_device_class": None, "original_device_class": None,
"original_icon": None, "original_icon": None,
"original_name": None, "original_name": None,
@ -250,6 +253,7 @@ async def test_update_entity(hass, client):
"entity_id": "test_domain.world", "entity_id": "test_domain.world",
"icon": "icon:after update", "icon": "icon:after update",
"name": "after update", "name": "after update",
"options": {},
"original_device_class": None, "original_device_class": None,
"original_icon": None, "original_icon": None,
"original_name": None, "original_name": None,
@ -259,6 +263,40 @@ async def test_update_entity(hass, client):
"reload_delay": 30, "reload_delay": 30,
} }
# UPDATE ENTITY OPTION
await client.send_json(
{
"id": 9,
"type": "config/entity_registry/update",
"entity_id": "test_domain.world",
"options_domain": "sensor",
"options": {"unit_of_measurement": "beard_second"},
}
)
msg = await client.receive_json()
assert msg["result"] == {
"entity_entry": {
"area_id": "mock-area-id",
"capabilities": None,
"config_entry_id": None,
"device_class": "custom_device_class",
"device_id": None,
"disabled_by": None,
"entity_category": None,
"entity_id": "test_domain.world",
"icon": "icon:after update",
"name": "after update",
"options": {"sensor": {"unit_of_measurement": "beard_second"}},
"original_device_class": None,
"original_icon": None,
"original_name": None,
"platform": "test_platform",
"unique_id": "1234",
},
}
async def test_update_entity_require_restart(hass, client): async def test_update_entity_require_restart(hass, client):
"""Test updating entity.""" """Test updating entity."""
@ -307,6 +345,7 @@ async def test_update_entity_require_restart(hass, client):
"entity_id": "test_domain.world", "entity_id": "test_domain.world",
"icon": None, "icon": None,
"name": None, "name": None,
"options": {},
"original_device_class": None, "original_device_class": None,
"original_icon": None, "original_icon": None,
"original_name": None, "original_name": None,
@ -411,6 +450,7 @@ async def test_update_entity_no_changes(hass, client):
"entity_id": "test_domain.world", "entity_id": "test_domain.world",
"icon": None, "icon": None,
"name": "name of entity", "name": "name of entity",
"options": {},
"original_device_class": None, "original_device_class": None,
"original_icon": None, "original_icon": None,
"original_name": None, "original_name": None,
@ -494,6 +534,7 @@ async def test_update_entity_id(hass, client):
"entity_id": "test_domain.planet", "entity_id": "test_domain.planet",
"icon": None, "icon": None,
"name": None, "name": None,
"options": {},
"original_device_class": None, "original_device_class": None,
"original_icon": None, "original_icon": None,
"original_name": None, "original_name": None,