updated lovelace dashboards and migrate tcp sensors to use serial component with SOCAT

This commit is contained in:
root
2025-04-30 15:01:46 -04:00
parent 4999b85b4e
commit f4ceef3cfe
117 changed files with 56924 additions and 8281 deletions

View File

@@ -4,7 +4,9 @@ Connect two Home Assistant instances via the Websocket API.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/remote_homeassistant/
"""
from __future__ import annotations
import asyncio
from typing import Optional
import copy
import fnmatch
import inspect
@@ -13,10 +15,15 @@ import re
from contextlib import suppress
import aiohttp
from aiohttp import ClientWebSocketResponse
import homeassistant.components.websocket_api.auth as api
import homeassistant.helpers.config_validation as cv
import voluptuous as vol
from homeassistant.config import DATA_CUSTOMIZE
try:
from homeassistant.core_config import DATA_CUSTOMIZE
except (ModuleNotFoundError, ImportError):
# hass 2024.10 or older
from homeassistant.config import DATA_CUSTOMIZE
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
from homeassistant.const import (CONF_ABOVE, CONF_ACCESS_TOKEN, CONF_BELOW,
CONF_DOMAINS, CONF_ENTITIES, CONF_ENTITY_ID,
@@ -28,10 +35,12 @@ from homeassistant.const import (CONF_ABOVE, CONF_ACCESS_TOKEN, CONF_BELOW,
from homeassistant.core import (Context, EventOrigin, HomeAssistant, callback,
split_entity_id)
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.reload import async_integration_yaml_config
from homeassistant.helpers.typing import ConfigType, HomeAssistantType
from homeassistant.helpers.service import async_register_admin_service
from homeassistant.helpers.typing import ConfigType
from homeassistant.setup import async_setup_component
from custom_components.remote_homeassistant.views import DiscoveryInfoView
@@ -52,6 +61,7 @@ CONF_INSTANCES = "instances"
CONF_SECURE = "secure"
CONF_SUBSCRIBE_EVENTS = "subscribe_events"
CONF_ENTITY_PREFIX = "entity_prefix"
CONF_ENTITY_FRIENDLY_NAME_PREFIX = "entity_friendly_name_prefix"
CONF_FILTER = "filter"
CONF_MAX_MSG_SIZE = "max_message_size"
@@ -64,6 +74,7 @@ STATE_RECONNECTING = "reconnecting"
STATE_DISCONNECTED = "disconnected"
DEFAULT_ENTITY_PREFIX = ""
DEFAULT_ENTITY_FRIENDLY_NAME_PREFIX = ""
INSTANCES_SCHEMA = vol.Schema(
{
@@ -103,7 +114,10 @@ INSTANCES_SCHEMA = vol.Schema(
],
),
vol.Optional(CONF_SUBSCRIBE_EVENTS): cv.ensure_list,
vol.Optional(CONF_ENTITY_PREFIX, default=DEFAULT_ENTITY_PREFIX): cv.string,
vol.Optional(CONF_ENTITY_PREFIX,
default=DEFAULT_ENTITY_PREFIX): cv.string,
vol.Optional(CONF_ENTITY_FRIENDLY_NAME_PREFIX,
default=DEFAULT_ENTITY_FRIENDLY_NAME_PREFIX): cv.string,
vol.Optional(CONF_LOAD_COMPONENTS): cv.ensure_list,
vol.Required(CONF_SERVICE_PREFIX, default="remote_"): cv.string,
vol.Optional(CONF_SERVICES): cv.ensure_list,
@@ -152,6 +166,7 @@ def async_yaml_to_config_entry(instance_conf):
CONF_FILTER,
CONF_SUBSCRIBE_EVENTS,
CONF_ENTITY_PREFIX,
CONF_ENTITY_FRIENDLY_NAME_PREFIX,
CONF_LOAD_COMPONENTS,
CONF_SERVICE_PREFIX,
CONF_SERVICES,
@@ -182,11 +197,11 @@ async def _async_update_config_entry_if_from_yaml(hass, entries_by_id, conf):
hass.config_entries.async_update_entry(entry, data=data, options=options)
async def setup_remote_instance(hass: HomeAssistantType):
async def setup_remote_instance(hass: HomeAssistant.core.HomeAssistant):
hass.http.register_view(DiscoveryInfoView())
async def async_setup(hass: HomeAssistantType, config: ConfigType):
async def async_setup(hass: HomeAssistant.core.HomeAssistant, config: ConfigType):
"""Set up the remote_homeassistant component."""
hass.data.setdefault(DOMAIN, {})
@@ -210,7 +225,7 @@ async def async_setup(hass: HomeAssistantType, config: ConfigType):
hass.async_create_task(setup_remote_instance(hass))
hass.helpers.service.async_register_admin_service(
async_register_admin_service(hass,
DOMAIN,
SERVICE_RELOAD,
_handle_reload,
@@ -246,12 +261,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
for domain in entry.options.get(CONF_LOAD_COMPONENTS, []):
hass.async_create_task(async_setup_component(hass, domain, {}))
await asyncio.gather(
*[
hass.config_entries.async_forward_entry_setup(entry, platform)
for platform in PLATFORMS
]
)
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
await remote.async_connect()
hass.async_create_task(setup_components_and_platforms())
@@ -292,7 +302,7 @@ async def _update_listener(hass, config_entry):
await hass.config_entries.async_reload(config_entry.entry_id)
class RemoteConnection(object):
class RemoteConnection:
"""A Websocket connection to a remote home-assistant instance."""
def __init__(self, hass, config_entry):
@@ -302,7 +312,7 @@ class RemoteConnection(object):
self._secure = config_entry.data.get(CONF_SECURE, False)
self._verify_ssl = config_entry.data.get(CONF_VERIFY_SSL, False)
self._access_token = config_entry.data.get(CONF_ACCESS_TOKEN)
self._max_msg_size = config_entry.data.get(CONF_MAX_MSG_SIZE)
self._max_msg_size = config_entry.data.get(CONF_MAX_MSG_SIZE, DEFAULT_MAX_MSG_SIZE)
# see homeassistant/components/influxdb/__init__.py
# for include/exclude logic
@@ -326,9 +336,12 @@ class RemoteConnection(object):
self._subscribe_events = set(
config_entry.options.get(CONF_SUBSCRIBE_EVENTS, []) + INTERNALLY_USED_EVENTS
)
self._entity_prefix = config_entry.options.get(CONF_ENTITY_PREFIX, "")
self._entity_prefix = config_entry.options.get(
CONF_ENTITY_PREFIX, "")
self._entity_friendly_name_prefix = config_entry.options.get(
CONF_ENTITY_FRIENDLY_NAME_PREFIX, "")
self._connection = None
self._connection : Optional[ClientWebSocketResponse] = None
self._heartbeat_task = None
self._is_stopping = False
self._entities = set()
@@ -349,6 +362,26 @@ class RemoteConnection(object):
return entity_id
return entity_id
def _prefixed_entity_friendly_name(self, entity_friendly_name):
if (self._entity_friendly_name_prefix
and entity_friendly_name.startswith(self._entity_friendly_name_prefix)
== False):
entity_friendly_name = (self._entity_friendly_name_prefix +
entity_friendly_name)
return entity_friendly_name
return entity_friendly_name
def _full_picture_url(self, url):
baseURL = "%s://%s:%s" % (
"https" if self._secure else "http",
self._entry.data[CONF_HOST],
self._entry.data[CONF_PORT],
)
if url.startswith(baseURL) == False:
url = baseURL + url
return url
return url
def set_connection_state(self, state):
"""Change current connection state."""
signal = f"remote_homeassistant_{self._entry.unique_id}"
@@ -445,7 +478,7 @@ class RemoteConnection(object):
async def _heartbeat_loop(self):
"""Send periodic heartbeats to remote instance."""
while not self._connection.closed:
while self._connection is not None and not self._connection.closed:
await asyncio.sleep(HEARTBEAT_INTERVAL)
_LOGGER.debug("Sending ping")
@@ -460,7 +493,7 @@ class RemoteConnection(object):
try:
await asyncio.wait_for(event.wait(), HEARTBEAT_TIMEOUT)
except asyncio.TimeoutError:
_LOGGER.error("heartbeat failed")
_LOGGER.warning("heartbeat failed")
# Schedule closing on event loop to avoid deadlock
asyncio.ensure_future(self._connection.close())
@@ -478,9 +511,13 @@ class RemoteConnection(object):
self.__id += 1
return _id
async def call(self, callback, message_type, **extra_args):
async def call(self, handler, message_type, **extra_args) -> None:
if self._connection is None:
_LOGGER.error("No remote websocket connection")
return
_id = self._next_id()
self._handlers[_id] = callback
self._handlers[_id] = handler
try:
await self._connection.send_json(
{"id": _id, "type": message_type, **extra_args}
@@ -511,7 +548,7 @@ class RemoteConnection(object):
asyncio.ensure_future(self.async_connect())
async def _recv(self):
while not self._connection.closed:
while self._connection is not None and not self._connection.closed:
try:
data = await self._connection.receive()
except aiohttp.client_exceptions.ClientError as err:
@@ -552,13 +589,13 @@ class RemoteConnection(object):
elif message["type"] == api.TYPE_AUTH_REQUIRED:
if self._access_token:
data = {"type": api.TYPE_AUTH, "access_token": self._access_token}
json_data = {"type": api.TYPE_AUTH, "access_token": self._access_token}
else:
_LOGGER.error("Access token required, but not provided")
self.set_connection_state(STATE_AUTH_REQUIRED)
return
try:
await self._connection.send_json(data)
await self._connection.send_json(json_data)
except Exception as err:
_LOGGER.error("could not send data to remote connection: %s", err)
break
@@ -570,12 +607,12 @@ class RemoteConnection(object):
return
else:
callback = self._handlers.get(message["id"])
if callback is not None:
if inspect.iscoroutinefunction(callback):
await callback(message)
handler = self._handlers.get(message["id"])
if handler is not None:
if inspect.iscoroutinefunction(handler):
await handler(message)
else:
callback(message)
handler(message)
await self._disconnected()
@@ -583,8 +620,8 @@ class RemoteConnection(object):
async def forward_event(event):
"""Send local event to remote instance.
The affected entity_id has to origin from that remote instance,
otherwise the event is dicarded.
The affected entity_id has to originate from that remote instance,
otherwise the event is discarded.
"""
event_data = event.data
service_data = event_data["service_data"]
@@ -627,7 +664,10 @@ class RemoteConnection(object):
data = {"id": _id, "type": event.event_type, **event_data}
_LOGGER.debug("forward event: %s", data)
if self._connection is None:
_LOGGER.error("There is no remote connecion to send send data to")
return
try:
await self._connection.send_json(data)
except Exception as err:
@@ -636,7 +676,7 @@ class RemoteConnection(object):
def state_changed(entity_id, state, attr):
"""Publish remote state change on local instance."""
domain, object_id = split_entity_id(entity_id)
domain, _object_id = split_entity_id(entity_id)
self._all_entity_names.add(entity_id)
@@ -661,7 +701,7 @@ class RemoteConnection(object):
try:
if f[CONF_BELOW] and float(state) < f[CONF_BELOW]:
_LOGGER.info(
"%s: ignoring state '%s', because " "below '%s'",
"%s: ignoring state '%s', because below '%s'",
entity_id,
state,
f[CONF_BELOW],
@@ -669,7 +709,7 @@ class RemoteConnection(object):
return
if f[CONF_ABOVE] and float(state) > f[CONF_ABOVE]:
_LOGGER.info(
"%s: ignoring state '%s', because " "above '%s'",
"%s: ignoring state '%s', because above '%s'",
entity_id,
state,
f[CONF_ABOVE],
@@ -680,15 +720,32 @@ class RemoteConnection(object):
entity_id = self._prefixed_entity_id(entity_id)
# Add local unique id
domain, object_id = split_entity_id(entity_id)
attr['unique_id'] = f"{self._entry.unique_id[:16]}_{entity_id}"
entity_registry = er.async_get(self._hass)
entity_registry.async_get_or_create(
domain=domain,
platform='remote_homeassistant',
unique_id=attr['unique_id'],
suggested_object_id=object_id,
)
# Add local customization data
if DATA_CUSTOMIZE in self._hass.data:
attr.update(self._hass.data[DATA_CUSTOMIZE].get(entity_id))
for attrId, value in attr.items():
if attrId == "friendly_name":
attr[attrId] = self._prefixed_entity_friendly_name(value)
if attrId == "entity_picture":
attr[attrId] = self._full_picture_url(value)
self._entities.add(entity_id)
self._hass.states.async_set(entity_id, state, attr)
def fire_event(message):
"""Publish remove event on local instance."""
"""Publish remote event on local instance."""
if message["type"] == "result":
return
@@ -730,6 +787,11 @@ class RemoteConnection(object):
entity_id = entity["entity_id"]
state = entity["state"]
attributes = entity["attributes"]
for attr, value in attributes.items():
if attr == "friendly_name":
attributes[attr] = self._prefixed_entity_friendly_name(value)
if attr == "entity_picture":
attributes[attr] = self._full_picture_url(value)
state_changed(entity_id, state, attributes)

View File

@@ -1,6 +1,8 @@
"""Config flow for Remote Home-Assistant integration."""
from __future__ import annotations
import logging
import enum
from typing import Any, Mapping
from urllib.parse import urlparse
@@ -16,6 +18,7 @@ from homeassistant.util import slugify
from . import async_yaml_to_config_entry
from .const import (CONF_ENTITY_PREFIX, # pylint:disable=unused-import
CONF_ENTITY_FRIENDLY_NAME_PREFIX,
CONF_EXCLUDE_DOMAINS, CONF_EXCLUDE_ENTITIES, CONF_FILTER,
CONF_INCLUDE_DOMAINS, CONF_INCLUDE_ENTITIES,
CONF_LOAD_COMPONENTS, CONF_MAIN, CONF_OPTIONS, CONF_REMOTE, CONF_REMOTE_CONNECTION,
@@ -31,11 +34,11 @@ ADD_NEW_EVENT = "add_new_event"
FILTER_OPTIONS = [CONF_ENTITY_ID, CONF_UNIT_OF_MEASUREMENT, CONF_ABOVE, CONF_BELOW]
def _filter_str(index, filter):
entity_id = filter[CONF_ENTITY_ID]
unit = filter[CONF_UNIT_OF_MEASUREMENT]
above = filter[CONF_ABOVE]
below = filter[CONF_BELOW]
def _filter_str(index, filter_conf: Mapping[str, str|float]):
entity_id = filter_conf[CONF_ENTITY_ID]
unit = filter_conf[CONF_UNIT_OF_MEASUREMENT]
above = filter_conf[CONF_ABOVE]
below = filter_conf[CONF_BELOW]
return f"{index+1}. {entity_id}, unit: {unit}, above: {above}, below: {below}"
@@ -50,8 +53,8 @@ async def validate_input(hass: core.HomeAssistant, conf):
conf[CONF_ACCESS_TOKEN],
conf.get(CONF_VERIFY_SSL, False),
)
except OSError:
raise CannotConnect()
except OSError as exc:
raise CannotConnect() from exc
return {"title": info["location_name"], "uuid": info["uuid"]}
@@ -91,9 +94,9 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
elif user_input[CONF_TYPE] == CONF_MAIN:
return await self.async_step_connection_details()
errors["base"] = "unknown"
return self.async_show_form(
step_id="user",
data_schema=vol.Schema(
@@ -129,7 +132,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
self._abort_if_unique_id_configured()
return self.async_create_entry(title=info["title"], data=user_input)
user_input = user_input or dict()
user_input = user_input or {}
host = user_input.get(CONF_HOST, self.prefill.get(CONF_HOST) or vol.UNDEFINED)
port = user_input.get(CONF_PORT, self.prefill.get(CONF_PORT) or vol.UNDEFINED)
secure = user_input.get(CONF_SECURE, self.prefill.get(CONF_SECURE) or vol.UNDEFINED)
@@ -149,10 +152,10 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
errors=errors,
)
async def async_step_zeroconf(self, info):
async def async_step_zeroconf(self, discovery_info):
"""Handle instance discovered via zeroconf."""
properties = info.properties
port = info.port
properties = discovery_info.properties
port = discovery_info.port
uuid = properties["uuid"]
await self.async_set_unique_id(uuid)
@@ -203,11 +206,11 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
def __init__(self, config_entry):
"""Initialize remote_homeassistant options flow."""
self.config_entry = config_entry
self.filters = None
self.events = None
self.options = None
self.filters : list[Any] | None = None
self.events : set[Any] | None = None
self.options : dict[str, Any] | None = None
async def async_step_init(self, user_input=None):
async def async_step_init(self, user_input : dict[str, str] | None = None):
"""Manage basic options."""
if self.config_entry.unique_id == REMOTE_ID:
return self.async_abort(reason="not_supported")
@@ -235,6 +238,14 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
)
},
): str,
vol.Optional(
CONF_ENTITY_FRIENDLY_NAME_PREFIX,
description={
"suggested_value": self.config_entry.options.get(
CONF_ENTITY_FRIENDLY_NAME_PREFIX
)
},
): str,
vol.Optional(
CONF_LOAD_COMPONENTS,
default=self._default(CONF_LOAD_COMPONENTS),
@@ -252,7 +263,7 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
async def async_step_domain_entity_filters(self, user_input=None):
"""Manage domain and entity filters."""
if user_input is not None:
if self.options is not None and user_input is not None:
self.options.update(user_input)
return await self.async_step_general_filters()
@@ -289,21 +300,25 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
# Each filter string is prefixed with a number (index in self.filter+1).
# Extract all of them and build the final filter list.
selected_indices = [
int(filter.split(".")[0]) - 1
for filter in user_input.get(CONF_FILTER, [])
int(filterItem.split(".")[0]) - 1
for filterItem in user_input.get(CONF_FILTER, [])
]
self.options[CONF_FILTER] = [self.filters[i] for i in selected_indices]
if self.options is not None:
self.options[CONF_FILTER] = [self.filters[i] for i in selected_indices] # type: ignore
return await self.async_step_events()
selected = user_input.get(CONF_FILTER, [])
new_filter = {conf: user_input.get(conf) for conf in FILTER_OPTIONS}
selected.append(_filter_str(len(self.filters), new_filter))
self.filters.append(new_filter)
selected.append(_filter_str(len(self.filters), new_filter)) # type: ignore
self.filters.append(new_filter) # type: ignore
else:
self.filters = self.config_entry.options.get(CONF_FILTER, [])
selected = [_filter_str(i, filter) for i, filter in enumerate(self.filters)]
selected = [_filter_str(i, filterItem) for i, filterItem in enumerate(self.filters)] # type: ignore
strings = [_filter_str(i, filter) for i, filter in enumerate(self.filters)]
if self.filters is None:
self.filters = []
strings = [_filter_str(i, filterItem) for i, filterItem in enumerate(self.filters)]
return self.async_show_form(
step_id="general_filters",
data_schema=vol.Schema(
@@ -322,13 +337,15 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
async def async_step_events(self, user_input=None):
"""Manage event options."""
if user_input is not None:
if ADD_NEW_EVENT not in user_input:
if ADD_NEW_EVENT not in user_input and self.options is not None:
self.options[CONF_SUBSCRIBE_EVENTS] = user_input.get(
CONF_SUBSCRIBE_EVENTS, []
)
return self.async_create_entry(title="", data=self.options)
selected = user_input.get(CONF_SUBSCRIBE_EVENTS, [])
if self.events is None:
self.events = set()
self.events.add(user_input[ADD_NEW_EVENT])
selected.append(user_input[ADD_NEW_EVENT])
else:

View File

@@ -13,6 +13,7 @@ CONF_SECURE = "secure"
CONF_API_PASSWORD = "api_password"
CONF_SUBSCRIBE_EVENTS = "subscribe_events"
CONF_ENTITY_PREFIX = "entity_prefix"
CONF_ENTITY_FRIENDLY_NAME_PREFIX = "entity_friendly_name_prefix"
CONF_MAX_MSG_SIZE = "max_message_size"
CONF_INCLUDE_DOMAINS = "include_domains"
@@ -20,7 +21,7 @@ CONF_INCLUDE_ENTITIES = "include_entities"
CONF_EXCLUDE_DOMAINS = "exclude_domains"
CONF_EXCLUDE_ENTITIES = "exclude_entities"
# FIXME: There seems to be ne way to make these strings translateable
# FIXME: There seems to be no way to make these strings translateable
CONF_MAIN = "Add a remote node"
CONF_REMOTE = "Setup as remote node"

View File

@@ -1,18 +1,19 @@
{
"domain": "remote_homeassistant",
"name": "Remote Home-Assistant",
"issue_tracker": "https://github.com/custom-components/remote_homeassistant/issues",
"documentation": "https://github.com/custom-components/remote_homeassistant",
"dependencies": ["http"],
"config_flow": true,
"codeowners": [
"@jaym25",
"@lukas-hetzenecker",
"@postlund"
],
"config_flow": true,
"dependencies": ["http"],
"documentation": "https://github.com/custom-components/remote_homeassistant",
"iot_class": "local_push",
"issue_tracker": "https://github.com/custom-components/remote_homeassistant/issues",
"requirements": [],
"version": "4.5",
"zeroconf": [
"_home-assistant._tcp.local."
],
"version": "3.11",
"iot_class": "local_push"
]
}

View File

@@ -1,5 +1,7 @@
"""Support for proxy services."""
from __future__ import annotations
import asyncio
from typing import Any
import voluptuous as vol
from homeassistant.exceptions import HomeAssistantError
@@ -78,14 +80,14 @@ class ProxyServices:
self.registered_services.append((domain, service))
async def _async_handle_service_call(self, event):
async def _async_handle_service_call(self, event) -> None:
"""Handle service call to proxy service."""
# An eception must be raised from the service call handler (thus method) in
# An exception must be raised from the service call handler (thus method) in
# order to end up in the frontend. The code below synchronizes reception of
# the service call result, so potential error message can be used as exception
# message. Not very pretty...
ev = asyncio.Event()
res = None
res : dict[str,Any] | None = None
def _resp(message):
nonlocal res
@@ -103,5 +105,5 @@ class ProxyServices:
)
await asyncio.wait_for(ev.wait(), SERVICE_CALL_LIMIT)
if not res["success"]:
if isinstance(res, dict) and not res["success"]:
raise HomeAssistantError(res["error"]["message"])

View File

@@ -3,8 +3,10 @@ from homeassistant.const import CONF_HOST, CONF_PORT, CONF_VERIFY_SSL
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity import DeviceInfo, Entity
from .const import DOMAIN, CONF_ENTITY_PREFIX, CONF_SECURE, CONF_MAX_MSG_SIZE, DEFAULT_MAX_MSG_SIZE
from .const import (DOMAIN, CONF_ENTITY_PREFIX,
CONF_ENTITY_FRIENDLY_NAME_PREFIX,
CONF_SECURE, CONF_MAX_MSG_SIZE,
DEFAULT_MAX_MSG_SIZE)
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up sensor based ok config entry."""
@@ -46,6 +48,7 @@ class ConnectionStatusSensor(Entity):
"verify_ssl": self._entry.data.get(CONF_VERIFY_SSL, False),
"max_msg_size": self._entry.data.get(CONF_MAX_MSG_SIZE, DEFAULT_MAX_MSG_SIZE),
"entity_prefix": self._entry.options.get(CONF_ENTITY_PREFIX, ""),
"entity_friendly_name_prefix": self._entry.options.get(CONF_ENTITY_FRIENDLY_NAME_PREFIX, ""),
"uuid": self.unique_id,
}

View File

@@ -1,2 +1,3 @@
reload:
name: Reload Remote Home-Assistant
description: Reload remote_homeassistant and re-process yaml configuration.

View File

@@ -30,22 +30,13 @@
"already_configured": "Bereits konfiguriert"
}
},
"state": {
"_": {
"disconnected": "Getrennt",
"connecting": "Verbindet",
"connected": "Verbunden",
"reconnecting": "Wiederverbinden",
"auth_invalid": "Ungültiger Zugangstoken",
"auth_required": "Authentifizierung erforderlich"
}
},
"options": {
"step": {
"init": {
"title": "Basis-Einstellungen (Schritt 1/4)",
"data": {
"entity_prefix": "Entitätspräfix (optional)",
"entity_friendly_name_prefix": "Entitätsname präfix (optional)",
"load_components": "Komponente laden (wenn nicht geladen)",
"service_prefix": "Servicepräfix",
"services": "Remote Services"

View File

@@ -30,22 +30,13 @@
"already_configured": "Already configured"
}
},
"state": {
"_": {
"disconnected": "Disconnected",
"connecting": "Connecting",
"connected": "Connected",
"reconnecting": "Re-connecting",
"auth_invalid": "Invalid access token",
"auth_required": "Authentication Required"
}
},
"options": {
"step": {
"init": {
"title": "Basic Options (step 1/4)",
"data": {
"entity_prefix": "Entity prefix (optional)",
"entity_friendly_name_prefix": "Entity name prefix (optional)",
"load_components": "Load component (if not loaded)",
"service_prefix": "Service prefix",
"services": "Remote Services"

View File

@@ -30,22 +30,13 @@
"already_configured": "Já configurado"
}
},
"state": {
"_": {
"disconnected": "Desconectado",
"connecting": "Conectando",
"connected": "Conectado",
"reconnecting": "Reconectando",
"auth_invalid": "Token de acesso inválido",
"auth_required": "Autentificação requerida"
}
},
"options": {
"step": {
"init": {
"title": "Opções básicas (passo 1/4)",
"data": {
"entity_prefix": "Prefixo da entidade (opcional)",
"entity_friendly_name_prefix": "Prefixo da entidade nombre (opcional)",
"load_components": "Carregar componente (se não estiver carregado)",
"service_prefix": "Prefixo do serviço",
"services": "Serviços remotos"

View File

@@ -1,6 +1,7 @@
import homeassistant
from homeassistant.components.http import HomeAssistantView
from homeassistant.helpers.system_info import async_get_system_info
from homeassistant.helpers.instance_id import async_get as async_get_instance_id
ATTR_INSTALLATION_TYPE = "installation_type"
@@ -17,7 +18,7 @@ class DiscoveryInfoView(HomeAssistantView):
system_info = await async_get_system_info(hass)
return self.json(
{
"uuid": await hass.helpers.instance_id.async_get(),
"uuid": await async_get_instance_id(hass),
"location_name": hass.config.location_name,
"ha_version": homeassistant.const.__version__,
"installation_type": system_info[ATTR_INSTALLATION_TYPE],