221 files

This commit is contained in:
Home Assistant Version Control
2026-10-10 15:24:58 +00:00
parent ae12b88c7d
commit bfafb4c28a
221 changed files with 73725 additions and 3277 deletions
+70 -39
View File
@@ -5,6 +5,7 @@ from __future__ import annotations
import asyncio import asyncio
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import ( from homeassistant.const import (
EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_START,
EVENT_HOMEASSISTANT_STARTED, EVENT_HOMEASSISTANT_STARTED,
@@ -18,6 +19,7 @@ from homeassistant.helpers import issue_registry as ir
from .automation_runs import async_setup_automation_runs from .automation_runs import async_setup_automation_runs
from .const import DOMAIN, LOGGER, PLATFORMS from .const import DOMAIN, LOGGER, PLATFORMS
from .core_compat import async_clear_custom_components_cache
from .dismissals import async_setup_dismissals from .dismissals import async_setup_dismissals
from .entity_filtering import async_setup_all_entity_ids_cache_invalidation from .entity_filtering import async_setup_all_entity_ids_cache_invalidation
from .integration_linking import link_sub_integrations, unlink_sub_integrations from .integration_linking import link_sub_integrations, unlink_sub_integrations
@@ -34,51 +36,80 @@ if TYPE_CHECKING:
from homeassistant.core import Event, HomeAssistant from homeassistant.core import Event, HomeAssistant
def _has_entries_waiting(hass: HomeAssistant, domains: set[str]) -> bool:
"""Return if a config entry of these domains is waiting to be set up.
When Home Assistant could not find the integration at startup, the entry
was never tried and is left not loaded. Any other state means its code
was found and ran, so a restart would not change a thing.
"""
return any(
entry.state is ConfigEntryState.NOT_LOADED
for domain in domains
for entry in hass.config_entries.async_entries(domain, include_disabled=False)
)
@callback
def _async_restart_for_sub_integrations(hass: HomeAssistant) -> bool:
"""Restart Home Assistant, or ask for it, so sub integrations get set up.
Returns if Spook can carry on setting up. Not when a restart is on its
way, as everything set up now would be torn down again right after.
"""
@callback
def _restart(_: Event | None = None) -> None:
"""Restart Home Assistant."""
hass.data["homeassistant_stop"] = asyncio.create_task(
hass.async_stop(RESTART_EXIT_CODE),
)
# Should be OK to restart. Better to do it before anything else started.
if hass.state == CoreState.starting:
LOGGER.info("Restarting Home Assistant to set up Spook's helpers")
_restart()
return False
# If all other fails, but we are not running yet... wait for it.
if hass.state == CoreState.not_running:
LOGGER.info("Restarting Home Assistant to set up Spook's helpers")
# Listen to both... just in case.
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START, _restart)
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STARTED, _restart)
return False
LOGGER.info(
"Home Assistant needs to be restarted for Spook to complete setting up",
)
ir.async_create_issue(
hass=hass,
domain=DOMAIN,
issue_id="restart_required",
is_fixable=True,
severity=ir.IssueSeverity.WARNING,
translation_key="restart_required",
)
return True
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up from a config entry.""" """Set up from a config entry."""
# Symlink all sub integrations from Spook to the parent integrations folder # Symlink all sub integrations from Spook to the parent integrations folder.
# if one is missing, we have to restart Home Assistant.
# This is a workaround for the fact that Home Assistant doesn't support # This is a workaround for the fact that Home Assistant doesn't support
# sub integrations. # sub integrations. The loader only scans custom_components once, so a
if await hass.async_add_executor_job(link_sub_integrations, hass): # freshly linked one needs it to look again, no restart required.
LOGGER.debug("Newly symlinked sub integrations, restarting Home Assistant") if linked := await hass.async_add_executor_job(link_sub_integrations, hass):
LOGGER.debug("Newly symlinked sub integrations, rescanning custom components")
async_clear_custom_components_cache(hass)
@callback # A helper made with a sub integration before its link went missing
def _restart(_: Event | None = None) -> None: # had nothing to set it up with when Home Assistant started, and that
"""Restart Home Assistant.""" # is not tried again. Only a restart picks it up.
hass.data["homeassistant_stop"] = asyncio.create_task( waiting = _has_entries_waiting(hass, linked)
hass.async_stop(RESTART_EXIT_CODE), if waiting and not _async_restart_for_sub_integrations(hass):
)
# User asked to restart Home Assistant in the config flow.
if hass.data.get(DOMAIN) == "Boo!":
_restart()
return False return False
# Should be OK to restart. Better to do it before anything else started.
if hass.state == CoreState.starting:
_restart()
return False
# If all other fails, but we are not running yet... wait for it.
if hass.state == CoreState.not_running:
# Listen to both... just in case.
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START, _restart)
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STARTED, _restart)
return False
LOGGER.info(
"Home Assistant needs to be restarted in for Spook to complete setting up",
)
ir.async_create_issue(
hass=hass,
domain=DOMAIN,
issue_id="restart_required",
is_fixable=True,
severity=ir.IssueSeverity.WARNING,
translation_key="restart_required",
)
# Forward async_setup_entry to ectoplasms # Forward async_setup_entry to ectoplasms
await async_forward_setup_entry(hass, entry) await async_forward_setup_entry(hass, entry)
+10
View File
@@ -54,6 +54,16 @@ repair_issue_present:
- critical - critical
- error - error
- warning - warning
is_available:
target:
entity: {}
fields:
behavior:
required: true
default: any
selector:
automation_behavior:
mode: condition
is_at_target_temperature: is_at_target_temperature:
target: target:
entity: entity:
+26 -32
View File
@@ -12,8 +12,9 @@ from homeassistant.config_entries import (
ConfigFlow, ConfigFlow,
ConfigFlowResult, ConfigFlowResult,
) )
from homeassistant.loader import async_get_integration
from .const import DOMAIN from .const import DOMAIN, NEWSLETTER_URL, REPOSITORY_URL, SPONSOR_URL
class UptimeConfigFlow(ConfigFlow, domain=DOMAIN): class UptimeConfigFlow(ConfigFlow, domain=DOMAIN):
@@ -42,15 +43,32 @@ class UptimeConfigFlow(ConfigFlow, domain=DOMAIN):
if self._disabled_entry is not None: if self._disabled_entry is not None:
return self.async_show_menu( return self.async_show_menu(
step_id="already_configured", step_id="already_configured",
menu_options=["enable_existing"], menu_options=["enable_existing", "keep_sleeping"],
) )
return self.async_abort(reason="already_spooked") return self.async_abort(reason="already_spooked")
integration = await async_get_integration(self.hass, DOMAIN)
if user_input is not None: if user_input is not None:
return await self.async_step_choice_restart() return self.async_create_entry(
title="Your homie",
data={},
description="spooked",
description_placeholders={
"documentation_url": str(integration.documentation),
"newsletter_url": NEWSLETTER_URL,
"repository_url": REPOSITORY_URL,
"sponsor_url": SPONSOR_URL,
},
)
return self.async_show_form(step_id="user", data_schema=vol.Schema({})) return self.async_show_form(
step_id="user",
data_schema=vol.Schema({}),
description_placeholders={
"issue_tracker_url": str(integration.issue_tracker),
},
)
async def async_step_already_configured( async def async_step_already_configured(
self, self,
@@ -63,7 +81,7 @@ class UptimeConfigFlow(ConfigFlow, domain=DOMAIN):
return self.async_show_menu( return self.async_show_menu(
step_id="already_configured", step_id="already_configured",
menu_options=["enable_existing"], menu_options=["enable_existing", "keep_sleeping"],
) )
async def async_step_enable_existing( async def async_step_enable_existing(
@@ -83,33 +101,9 @@ class UptimeConfigFlow(ConfigFlow, domain=DOMAIN):
return self.async_abort(reason="enable_failed") return self.async_abort(reason="enable_failed")
async def async_step_choice_restart( async def async_step_keep_sleeping(
self, self,
_: dict[str, Any] | None = None, _: dict[str, Any] | None = None,
) -> ConfigFlowResult: ) -> ConfigFlowResult:
"""Handle the user's choice. """Leave the existing disabled Spook config entry alone."""
return self.async_abort(reason="kept_sleeping")
Allows the user to choose to restart now or later.
"""
return self.async_show_menu(
step_id="choice_restart",
menu_options=["restart_now", "restart_later"],
)
async def async_step_restart_later(
self,
_: dict[str, Any] | None = None,
) -> ConfigFlowResult:
"""Handle restart later case."""
return self.async_create_entry(title="Your homie", data={})
async def async_step_restart_now(
self,
_: dict[str, Any] | None = None,
) -> ConfigFlowResult:
"""Handle restart now case.
Sets a flag, so the integraton setup knows it can go ahead and restart.
"""
self.hass.data[DOMAIN] = "Boo!"
return await self.async_step_restart_later()
+5
View File
@@ -8,6 +8,11 @@ from homeassistant.const import Platform
DOMAIN: Final = "spook" DOMAIN: Final = "spook"
LOGGER = logging.getLogger(__package__) LOGGER = logging.getLogger(__package__)
# Asked for once, at the end of setting Spook up, and nowhere else.
NEWSLETTER_URL: Final = "https://frenck.dev/newsletter/"
REPOSITORY_URL: Final = "https://github.com/frenck/spook"
SPONSOR_URL: Final = "https://github.com/sponsors/frenck"
PLATFORMS: Final = [ PLATFORMS: Final = [
Platform.BINARY_SENSOR, Platform.BINARY_SENSOR,
Platform.BUTTON, Platform.BUTTON,
@@ -14,6 +14,7 @@ from homeassistant.components.blueprint.importer import fetch_blueprint_from_url
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
from ....const import DOMAIN as SPOOK_DOMAIN
from ....services import AbstractSpookAdminService from ....services import AbstractSpookAdminService
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -37,17 +38,26 @@ class SpookService(AbstractSpookAdminService):
call.data["url"], call.data["url"],
) )
except (TimeoutError, aiohttp.ClientError) as err: except (TimeoutError, aiohttp.ClientError) as err:
msg = "Error fetching blueprint from URL" raise HomeAssistantError(
raise HomeAssistantError(msg) from err translation_domain=SPOOK_DOMAIN,
translation_key="blueprint_fetch_failed",
) from err
if imported_blueprint is None: if imported_blueprint is None:
msg = "This url is not supported" raise HomeAssistantError(
raise HomeAssistantError(msg) translation_domain=SPOOK_DOMAIN,
translation_key="blueprint_url_not_supported",
)
domain_blueprints: dict[str, DomainBlueprints] = self.hass.data.get(DOMAIN, {}) domain_blueprints: dict[str, DomainBlueprints] = self.hass.data.get(DOMAIN, {})
if imported_blueprint.blueprint.domain not in domain_blueprints: if imported_blueprint.blueprint.domain not in domain_blueprints:
msg = f"Unsupported domain: {imported_blueprint.blueprint.domain}" raise HomeAssistantError(
raise HomeAssistantError(msg) translation_domain=SPOOK_DOMAIN,
translation_key="blueprint_domain_not_supported",
translation_placeholders={
"domain": imported_blueprint.blueprint.domain,
},
)
imported_blueprint.blueprint.update_metadata(source_url=call.data["url"]) imported_blueprint.blueprint.update_metadata(source_url=call.data["url"])
@@ -59,8 +69,12 @@ class SpookService(AbstractSpookAdminService):
imported_blueprint.suggested_filename, imported_blueprint.suggested_filename,
) )
except FileAlreadyExists as ex: except FileAlreadyExists as ex:
msg = "File already exists" raise HomeAssistantError(
raise HomeAssistantError(msg) from ex translation_domain=SPOOK_DOMAIN,
translation_key="blueprint_file_exists",
) from ex
except OSError as err: except OSError as err:
msg = "Error writing file" raise HomeAssistantError(
raise HomeAssistantError(msg) from err translation_domain=SPOOK_DOMAIN,
translation_key="blueprint_write_failed",
) from err
@@ -7,11 +7,11 @@ from homeassistant.const import (
EVENT_COMPONENT_LOADED, EVENT_COMPONENT_LOADED,
) )
from homeassistant.helpers import entity_registry as er from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.entity_platform import DATA_ENTITY_PLATFORM, EntityPlatform
from ....const import LOGGER from ....const import LOGGER
from ....entity_filtering import async_filter_known_entity_ids, async_get_all_entity_ids from ....entity_filtering import async_filter_known_entity_ids, async_get_all_entity_ids
from ....entity_suggestions import async_describe_unknown_entities from ....entity_suggestions import async_describe_unknown_entities
from ....helper_sources import async_group_members
from ....repairs import AbstractSpookRepair from ....repairs import AbstractSpookRepair
@@ -35,55 +35,35 @@ class SpookRepair(AbstractSpookRepair):
known_entity_ids = async_get_all_entity_ids(self.hass) known_entity_ids = async_get_all_entity_ids(self.hass)
platforms: list[EntityPlatform] | None for entity, members in async_group_members(self.hass):
if not (platforms := self.hass.data[DATA_ENTITY_PLATFORM].get(self.domain)): self.possible_issue_ids.add(entity.entity_id)
return # Nothing to do.
# Taken as a snapshot: describing what is missing can hand the event if unknown_entities := async_filter_known_entity_ids(
# loop a turn, and a change to the live collection during it ends the self.hass, entity_ids=members, known_entity_ids=known_entity_ids
# inspection in a `RuntimeError`. #1558. ):
for platform in list(platforms): described = await async_describe_unknown_entities(
# We don't want to check the old style group platform self.hass, sorted(unknown_entities)
for entity in list(platform.entities.values()): )
self.possible_issue_ids.add(entity.entity_id) self.async_create_issue(
members = [] issue_id=entity.entity_id,
if platform.domain == group.DOMAIN: references=unknown_entities,
members = entity.tracking is_fixable=True,
elif hasattr(entity, "_entity_ids"): data={
# pylint: disable-next=protected-access "group_entity_id": entity.entity_id,
members = entity._entity_ids # noqa: SLF001 # What the fix checks again before dropping any.
elif hasattr(entity, "_entities"): "group_unknown_entity_ids": ",".join(sorted(unknown_entities)),
# pylint: disable-next=protected-access "group": entity.name,
members = entity._entities # noqa: SLF001 "entities": described,
},
if unknown_entities := async_filter_known_entity_ids( translation_placeholders={
self.hass, entity_ids=members, known_entity_ids=known_entity_ids "entities": described,
): "group": entity.name,
described = await async_describe_unknown_entities( "entity_id": entity.entity_id,
self.hass, sorted(unknown_entities) },
) )
self.async_create_issue( LOGGER.debug(
issue_id=entity.entity_id, "Spook found unknown member entities in %s "
references=unknown_entities, "and created an issue for it; Entities: %s",
is_fixable=True, entity.entity_id,
data={ ", ".join(unknown_entities),
"group_entity_id": entity.entity_id, )
# What the fix checks again before dropping any.
"group_unknown_entity_ids": ",".join(
sorted(unknown_entities)
),
"group": entity.name,
"entities": described,
},
translation_placeholders={
"entities": described,
"group": entity.name,
"entity_id": entity.entity_id,
},
)
LOGGER.debug(
"Spook found unknown member entities in %s "
"and created an issue for it; Entities: %s",
entity.entity_id,
", ".join(unknown_entities),
)
@@ -3,8 +3,8 @@
from __future__ import annotations from __future__ import annotations
from homeassistant.components import homeassistant from homeassistant.components import homeassistant
from homeassistant.const import __version__ from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
from homeassistant.helpers.device_registry import DeviceInfo from homeassistant.loader import async_get_loaded_integration
from ...const import DOMAIN from ...const import DOMAIN
from ...entity import SpookEntity, SpookEntityDescription from ...entity import SpookEntity, SpookEntityDescription
@@ -16,10 +16,21 @@ class HomeAssistantSpookEntity(SpookEntity):
def __init__(self, description: SpookEntityDescription) -> None: def __init__(self, description: SpookEntityDescription) -> None:
"""Initialize the entity.""" """Initialize the entity."""
super().__init__(description=description) super().__init__(description=description)
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, homeassistant.DOMAIN)},
manufacturer="Home Assistant",
name="Home Assistant",
sw_version=__version__,
)
self._attr_unique_id = f"{homeassistant.DOMAIN}_{description.key}" self._attr_unique_id = f"{homeassistant.DOMAIN}_{description.key}"
@property
def device_info(self) -> DeviceInfo:
"""Return the device, which is Spook's, so it runs Spook's version.
Read once the entity is added to Home Assistant, as the version comes
from the loaded integration.
"""
version = async_get_loaded_integration(self.hass, DOMAIN).version
return DeviceInfo(
identifiers={(DOMAIN, homeassistant.DOMAIN)},
manufacturer="Spook 👻",
name="Home Assistant",
sw_version=str(version) if version else None,
configuration_url="https://spook.boo/devices-entities",
entry_type=DeviceEntryType.SERVICE,
)
@@ -13,9 +13,12 @@ from homeassistant.components.homeassistant.exposed_entities import (
async_expose_entity, async_expose_entity,
) )
from homeassistant.const import ATTR_ENTITY_ID from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError from homeassistant.exceptions import ServiceValidationError
from homeassistant.helpers import config_validation as cv, entity_registry as er from homeassistant.helpers import config_validation as cv, entity_registry as er
from ....const import DOMAIN
from ....errors import entity_not_found
if TYPE_CHECKING: if TYPE_CHECKING:
from homeassistant.core import HomeAssistant, ServiceCall from homeassistant.core import HomeAssistant, ServiceCall
@@ -41,13 +44,20 @@ def async_config_entry_ids(hass: HomeAssistant, call: ServiceCall) -> list[str]:
domains: list[str] = call.data.get(CONF_DOMAIN, []) domains: list[str] = call.data.get(CONF_DOMAIN, [])
if not entry_ids and not domains: if not entry_ids and not domains:
msg = "Name the integration entries to change, or their integration" raise ServiceValidationError(
raise ServiceValidationError(msg) translation_domain=DOMAIN,
translation_key="integration_entries_required",
)
for domain in domains: for domain in domains:
if not (entries := hass.config_entries.async_entries(domain)): if not (entries := hass.config_entries.async_entries(domain)):
msg = f"The {domain} integration has no entries" raise ServiceValidationError(
raise ServiceValidationError(msg) translation_domain=DOMAIN,
translation_key="integration_without_entries",
translation_placeholders={
"domain": domain,
},
)
entry_ids.extend( entry_ids.extend(
entry.entry_id for entry in entries if entry.entry_id not in entry_ids entry.entry_id for entry in entries if entry.entry_id not in entry_ids
) )
@@ -82,8 +92,7 @@ def async_set_voice_assistant_exposure(
hass.states.get(entity_id) is None hass.states.get(entity_id) is None
and entity_registry.async_get(entity_id) is None and entity_registry.async_get(entity_id) is None
): ):
msg = f"Unknown entity: {entity_id}" raise entity_not_found(entity_id)
raise HomeAssistantError(msg)
for entity_id in entity_ids: for entity_id in entity_ids:
for assistant in call.data[CONF_ASSISTANTS]: for assistant in call.data[CONF_ASSISTANTS]:
@@ -7,9 +7,9 @@ from typing import TYPE_CHECKING
import voluptuous as vol import voluptuous as vol
from homeassistant.components.homeassistant import DOMAIN from homeassistant.components.homeassistant import DOMAIN
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import area_registry as ar, config_validation as cv from homeassistant.helpers import area_registry as ar, config_validation as cv
from ....errors import area_not_found
from ....services import AbstractSpookAdminService from ....services import AbstractSpookAdminService
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -30,8 +30,7 @@ class SpookService(AbstractSpookAdminService):
"""Handle the service call.""" """Handle the service call."""
area_registry = ar.async_get(self.hass) area_registry = ar.async_get(self.hass)
if not (area := area_registry.async_get_area(call.data["area_id"])): if not (area := area_registry.async_get_area(call.data["area_id"])):
msg = f"Area {call.data['area_id']} not found" raise area_not_found(call.data["area_id"])
raise HomeAssistantError(msg)
aliases = area.aliases.copy() aliases = area.aliases.copy()
area_registry.async_update( area_registry.async_update(
@@ -7,12 +7,12 @@ from typing import TYPE_CHECKING
import voluptuous as vol import voluptuous as vol
from homeassistant.components.homeassistant import DOMAIN from homeassistant.components.homeassistant import DOMAIN
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import ( from homeassistant.helpers import (
config_validation as cv, config_validation as cv,
floor_registry as fr, floor_registry as fr,
) )
from ....errors import floor_not_found
from ....services import AbstractSpookAdminService from ....services import AbstractSpookAdminService
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -33,8 +33,7 @@ class SpookService(AbstractSpookAdminService):
"""Handle the service call.""" """Handle the service call."""
floor_registry = fr.async_get(self.hass) floor_registry = fr.async_get(self.hass)
if not (floor := floor_registry.async_get_floor(call.data["floor_id"])): if not (floor := floor_registry.async_get_floor(call.data["floor_id"])):
msg = f"Floor {call.data['floor_id']} not found" raise floor_not_found(call.data["floor_id"])
raise HomeAssistantError(msg)
aliases = floor.aliases.copy() aliases = floor.aliases.copy()
floor_registry.async_update( floor_registry.async_update(
@@ -7,13 +7,13 @@ from typing import TYPE_CHECKING
import voluptuous as vol import voluptuous as vol
from homeassistant.components.homeassistant import DOMAIN from homeassistant.components.homeassistant import DOMAIN
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import ( from homeassistant.helpers import (
area_registry as ar, area_registry as ar,
config_validation as cv, config_validation as cv,
floor_registry as fr, floor_registry as fr,
) )
from ....errors import floor_not_found
from ....services import AbstractSpookAdminService from ....services import AbstractSpookAdminService
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -34,8 +34,7 @@ class SpookService(AbstractSpookAdminService):
"""Handle the service call.""" """Handle the service call."""
floor_registry = fr.async_get(self.hass) floor_registry = fr.async_get(self.hass)
if not floor_registry.async_get_floor(call.data["floor_id"]): if not floor_registry.async_get_floor(call.data["floor_id"]):
msg = f"Floor {call.data['floor_id']} not found" raise floor_not_found(call.data["floor_id"])
raise HomeAssistantError(msg)
area_registry = ar.async_get(self.hass) area_registry = ar.async_get(self.hass)
for area_id in call.data["area_id"]: for area_id in call.data["area_id"]:
@@ -7,7 +7,6 @@ from typing import TYPE_CHECKING
import voluptuous as vol import voluptuous as vol
from homeassistant.components.homeassistant import DOMAIN from homeassistant.components.homeassistant import DOMAIN
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import ( from homeassistant.helpers import (
area_registry as ar, area_registry as ar,
config_validation as cv, config_validation as cv,
@@ -15,6 +14,7 @@ from homeassistant.helpers import (
) )
from ....core_compat import async_update_any_device from ....core_compat import async_update_any_device
from ....errors import area_not_found
from ....services import AbstractSpookAdminService from ....services import AbstractSpookAdminService
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -35,8 +35,7 @@ class SpookService(AbstractSpookAdminService):
"""Handle the service call.""" """Handle the service call."""
area_registry = ar.async_get(self.hass) area_registry = ar.async_get(self.hass)
if not area_registry.async_get_area(call.data["area_id"]): if not area_registry.async_get_area(call.data["area_id"]):
msg = f"Area {call.data['area_id']} not found" raise area_not_found(call.data["area_id"])
raise HomeAssistantError(msg)
device_registry = dr.async_get(self.hass) device_registry = dr.async_get(self.hass)
for device_id in call.data["device_id"]: for device_id in call.data["device_id"]:
@@ -7,13 +7,13 @@ from typing import TYPE_CHECKING
import voluptuous as vol import voluptuous as vol
from homeassistant.components.homeassistant import DOMAIN from homeassistant.components.homeassistant import DOMAIN
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import ( from homeassistant.helpers import (
area_registry as ar, area_registry as ar,
config_validation as cv, config_validation as cv,
entity_registry as er, entity_registry as er,
) )
from ....errors import area_not_found
from ....services import AbstractSpookAdminService from ....services import AbstractSpookAdminService
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -34,8 +34,7 @@ class SpookService(AbstractSpookAdminService):
"""Handle the service call.""" """Handle the service call."""
area_registry = ar.async_get(self.hass) area_registry = ar.async_get(self.hass)
if not area_registry.async_get_area(call.data["area_id"]): if not area_registry.async_get_area(call.data["area_id"]):
msg = f"Area {call.data['area_id']} not found" raise area_not_found(call.data["area_id"])
raise HomeAssistantError(msg)
entity_registry = er.async_get(self.hass) entity_registry = er.async_get(self.hass)
for entity_id in call.data["entity_id"]: for entity_id in call.data["entity_id"]:
@@ -7,12 +7,12 @@ from typing import TYPE_CHECKING
import voluptuous as vol import voluptuous as vol
from homeassistant.components.homeassistant import DOMAIN from homeassistant.components.homeassistant import DOMAIN
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import ( from homeassistant.helpers import (
area_registry as ar, area_registry as ar,
config_validation as cv, config_validation as cv,
) )
from ....errors import area_not_found
from ....services import AbstractSpookAdminService from ....services import AbstractSpookAdminService
from ..labels import async_check_labels_exist from ..labels import async_check_labels_exist
@@ -41,8 +41,7 @@ class SpookService(AbstractSpookAdminService):
updates: dict[str, set[str]] = {} updates: dict[str, set[str]] = {}
for area_id in call.data["area_id"]: for area_id in call.data["area_id"]:
if (area_entry := area_registry.async_get_area(area_id)) is None: if (area_entry := area_registry.async_get_area(area_id)) is None:
msg = f"Area {area_id} not found" raise area_not_found(area_id)
raise HomeAssistantError(msg)
labels = area_entry.labels.copy() labels = area_entry.labels.copy()
labels.update(call.data["label_id"]) labels.update(call.data["label_id"])
@@ -7,13 +7,13 @@ from typing import TYPE_CHECKING
import voluptuous as vol import voluptuous as vol
from homeassistant.components.homeassistant import DOMAIN from homeassistant.components.homeassistant import DOMAIN
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import ( from homeassistant.helpers import (
config_validation as cv, config_validation as cv,
device_registry as dr, device_registry as dr,
) )
from ....core_compat import async_update_any_device from ....core_compat import async_update_any_device
from ....errors import device_not_found
from ....services import AbstractSpookAdminService from ....services import AbstractSpookAdminService
from ..labels import async_check_labels_exist from ..labels import async_check_labels_exist
@@ -42,8 +42,7 @@ class SpookService(AbstractSpookAdminService):
updates: dict[str, set[str]] = {} updates: dict[str, set[str]] = {}
for device_id in call.data["device_id"]: for device_id in call.data["device_id"]:
if (device_entry := device_registry.async_get(device_id)) is None: if (device_entry := device_registry.async_get(device_id)) is None:
msg = f"Device {device_id} not found" raise device_not_found(device_id)
raise HomeAssistantError(msg)
labels = device_entry.labels.copy() labels = device_entry.labels.copy()
labels.update(call.data["label_id"]) labels.update(call.data["label_id"])
@@ -7,12 +7,12 @@ from typing import TYPE_CHECKING
import voluptuous as vol import voluptuous as vol
from homeassistant.components.homeassistant import DOMAIN from homeassistant.components.homeassistant import DOMAIN
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import ( from homeassistant.helpers import (
config_validation as cv, config_validation as cv,
entity_registry as er, entity_registry as er,
) )
from ....errors import entity_not_found
from ....services import AbstractSpookAdminService from ....services import AbstractSpookAdminService
from ..labels import async_check_labels_exist from ..labels import async_check_labels_exist
@@ -41,8 +41,7 @@ class SpookService(AbstractSpookAdminService):
updates: dict[str, set[str]] = {} updates: dict[str, set[str]] = {}
for entity_id in call.data["entity_id"]: for entity_id in call.data["entity_id"]:
if (entity_entry := entity_registry.async_get(entity_id)) is None: if (entity_entry := entity_registry.async_get(entity_id)) is None:
msg = f"Entity {entity_id} not found" raise entity_not_found(entity_id)
raise HomeAssistantError(msg)
labels = entity_entry.labels.copy() labels = entity_entry.labels.copy()
labels.update(call.data["label_id"]) labels.update(call.data["label_id"])
@@ -7,9 +7,9 @@ from typing import TYPE_CHECKING
import voluptuous as vol import voluptuous as vol
from homeassistant.components.homeassistant import DOMAIN from homeassistant.components.homeassistant import DOMAIN
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
from ....errors import config_entry_not_found
from ....services import AbstractSpookAdminService from ....services import AbstractSpookAdminService
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -30,8 +30,7 @@ class SpookService(AbstractSpookAdminService):
call.data["config_entry_id"], call.data["config_entry_id"],
) )
): ):
msg = f"Config entry not found: {call.data['config_entry_id']}" raise config_entry_not_found(call.data["config_entry_id"])
raise HomeAssistantError(msg)
self.hass.config_entries.async_update_entry( self.hass.config_entries.async_update_entry(
entry, entry,
@@ -10,6 +10,8 @@ from homeassistant.components.homeassistant import DOMAIN
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
from ....const import DOMAIN as SPOOK_DOMAIN
from ....errors import user_not_found
from ....services import AbstractSpookAdminService from ....services import AbstractSpookAdminService
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -31,11 +33,15 @@ class SpookService(AbstractSpookAdminService):
for user_id in call.data["user_id"]: for user_id in call.data["user_id"]:
user = await self.hass.auth.async_get_user(user_id) user = await self.hass.auth.async_get_user(user_id)
if user is None: if user is None:
message = f"Could not find user: {user_id}" raise user_not_found(user_id)
raise HomeAssistantError(message)
if user.system_generated: if user.system_generated:
message = f"Cannot disable a system-generated user: {user_id}" raise HomeAssistantError(
raise HomeAssistantError(message) translation_domain=SPOOK_DOMAIN,
translation_key="cannot_disable_system_user",
translation_placeholders={
"user_id": user_id,
},
)
users.append(user) users.append(user)
for user in users: for user in users:
@@ -7,9 +7,9 @@ from typing import TYPE_CHECKING
import voluptuous as vol import voluptuous as vol
from homeassistant.components.homeassistant import DOMAIN from homeassistant.components.homeassistant import DOMAIN
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
from ....errors import config_entry_not_found
from ....services import AbstractSpookAdminService from ....services import AbstractSpookAdminService
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -30,8 +30,7 @@ class SpookService(AbstractSpookAdminService):
call.data["config_entry_id"], call.data["config_entry_id"],
) )
): ):
msg = f"Config entry not found: {call.data['config_entry_id']}" raise config_entry_not_found(call.data["config_entry_id"])
raise HomeAssistantError(msg)
self.hass.config_entries.async_update_entry( self.hass.config_entries.async_update_entry(
entry, entry,
@@ -10,6 +10,8 @@ from homeassistant.components.homeassistant import DOMAIN
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
from ....const import DOMAIN as SPOOK_DOMAIN
from ....errors import user_not_found
from ....services import AbstractSpookAdminService from ....services import AbstractSpookAdminService
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -31,11 +33,15 @@ class SpookService(AbstractSpookAdminService):
for user_id in call.data["user_id"]: for user_id in call.data["user_id"]:
user = await self.hass.auth.async_get_user(user_id) user = await self.hass.auth.async_get_user(user_id)
if user is None: if user is None:
message = f"Could not find user: {user_id}" raise user_not_found(user_id)
raise HomeAssistantError(message)
if user.system_generated: if user.system_generated:
message = f"Cannot enable a system-generated user: {user_id}" raise HomeAssistantError(
raise HomeAssistantError(message) translation_domain=SPOOK_DOMAIN,
translation_key="cannot_enable_system_user",
translation_placeholders={
"user_id": user_id,
},
)
users.append(user) users.append(user)
for user in users: for user in users:
@@ -7,9 +7,9 @@ from typing import TYPE_CHECKING
import voluptuous as vol import voluptuous as vol
from homeassistant.components.homeassistant import DOMAIN from homeassistant.components.homeassistant import DOMAIN
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import area_registry as ar, config_validation as cv from homeassistant.helpers import area_registry as ar, config_validation as cv
from ....errors import area_not_found
from ....services import AbstractSpookAdminService from ....services import AbstractSpookAdminService
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -30,8 +30,7 @@ class SpookService(AbstractSpookAdminService):
"""Handle the service call.""" """Handle the service call."""
area_registry = ar.async_get(self.hass) area_registry = ar.async_get(self.hass)
if not (area := area_registry.async_get_area(call.data["area_id"])): if not (area := area_registry.async_get_area(call.data["area_id"])):
msg = f"Area {call.data['area_id']} not found" raise area_not_found(call.data["area_id"])
raise HomeAssistantError(msg)
aliases = area.aliases.copy() aliases = area.aliases.copy()
area_registry.async_update( area_registry.async_update(
@@ -7,9 +7,9 @@ from typing import TYPE_CHECKING
import voluptuous as vol import voluptuous as vol
from homeassistant.components.homeassistant import DOMAIN from homeassistant.components.homeassistant import DOMAIN
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv, floor_registry as fr from homeassistant.helpers import config_validation as cv, floor_registry as fr
from ....errors import floor_not_found
from ....services import AbstractSpookAdminService from ....services import AbstractSpookAdminService
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -30,8 +30,7 @@ class SpookService(AbstractSpookAdminService):
"""Handle the service call.""" """Handle the service call."""
floor_registry = fr.async_get(self.hass) floor_registry = fr.async_get(self.hass)
if not (floor := floor_registry.async_get_floor(call.data["floor_id"])): if not (floor := floor_registry.async_get_floor(call.data["floor_id"])):
msg = f"Floor {call.data['floor_id']} not found" raise floor_not_found(call.data["floor_id"])
raise HomeAssistantError(msg)
aliases = floor.aliases.copy() aliases = floor.aliases.copy()
floor_registry.async_update( floor_registry.async_update(
@@ -7,12 +7,12 @@ from typing import TYPE_CHECKING
import voluptuous as vol import voluptuous as vol
from homeassistant.components.homeassistant import DOMAIN from homeassistant.components.homeassistant import DOMAIN
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import ( from homeassistant.helpers import (
area_registry as ar, area_registry as ar,
config_validation as cv, config_validation as cv,
) )
from ....errors import area_not_found
from ....services import AbstractSpookAdminService from ....services import AbstractSpookAdminService
from ..labels import async_check_labels_exist from ..labels import async_check_labels_exist
@@ -41,8 +41,7 @@ class SpookService(AbstractSpookAdminService):
updates: dict[str, set[str]] = {} updates: dict[str, set[str]] = {}
for area_id in call.data["area_id"]: for area_id in call.data["area_id"]:
if (area_entry := area_registry.async_get_area(area_id)) is None: if (area_entry := area_registry.async_get_area(area_id)) is None:
msg = f"Area {area_id} not found" raise area_not_found(area_id)
raise HomeAssistantError(msg)
labels = area_entry.labels.copy() labels = area_entry.labels.copy()
labels.difference_update(call.data["label_id"]) labels.difference_update(call.data["label_id"])
@@ -7,13 +7,13 @@ from typing import TYPE_CHECKING
import voluptuous as vol import voluptuous as vol
from homeassistant.components.homeassistant import DOMAIN from homeassistant.components.homeassistant import DOMAIN
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import ( from homeassistant.helpers import (
config_validation as cv, config_validation as cv,
device_registry as dr, device_registry as dr,
) )
from ....core_compat import async_update_any_device from ....core_compat import async_update_any_device
from ....errors import device_not_found
from ....services import AbstractSpookAdminService from ....services import AbstractSpookAdminService
from ..labels import async_check_labels_exist from ..labels import async_check_labels_exist
@@ -42,8 +42,7 @@ class SpookService(AbstractSpookAdminService):
updates: dict[str, set[str]] = {} updates: dict[str, set[str]] = {}
for device_id in call.data["device_id"]: for device_id in call.data["device_id"]:
if (device_entry := device_registry.async_get(device_id)) is None: if (device_entry := device_registry.async_get(device_id)) is None:
msg = f"Device {device_id} not found" raise device_not_found(device_id)
raise HomeAssistantError(msg)
labels = device_entry.labels.copy() labels = device_entry.labels.copy()
labels.difference_update(call.data["label_id"]) labels.difference_update(call.data["label_id"])
@@ -7,12 +7,12 @@ from typing import TYPE_CHECKING
import voluptuous as vol import voluptuous as vol
from homeassistant.components.homeassistant import DOMAIN from homeassistant.components.homeassistant import DOMAIN
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import ( from homeassistant.helpers import (
config_validation as cv, config_validation as cv,
entity_registry as er, entity_registry as er,
) )
from ....errors import entity_not_found
from ....services import AbstractSpookAdminService from ....services import AbstractSpookAdminService
from ..labels import async_check_labels_exist from ..labels import async_check_labels_exist
@@ -41,8 +41,7 @@ class SpookService(AbstractSpookAdminService):
updates: dict[str, set[str]] = {} updates: dict[str, set[str]] = {}
for entity_id in call.data["entity_id"]: for entity_id in call.data["entity_id"]:
if (entity_entry := entity_registry.async_get(entity_id)) is None: if (entity_entry := entity_registry.async_get(entity_id)) is None:
msg = f"Entity {entity_id} not found" raise entity_not_found(entity_id)
raise HomeAssistantError(msg)
labels = entity_entry.labels.copy() labels = entity_entry.labels.copy()
labels.difference_update(call.data["label_id"]) labels.difference_update(call.data["label_id"])
@@ -12,7 +12,7 @@ from homeassistant.const import RESTART_EXIT_CODE
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
from ....const import LOGGER from ....const import DOMAIN as SPOOK_DOMAIN, LOGGER
from ....services import AbstractSpookAdminService, ReplaceExistingService from ....services import AbstractSpookAdminService, ReplaceExistingService
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -42,9 +42,9 @@ class SpookService(AbstractSpookAdminService, ReplaceExistingService):
return return
if not self.overriden_service: if not self.overriden_service:
msg = "Spook encountered an error while restarting Home Assistant."
raise HomeAssistantError( raise HomeAssistantError(
msg, translation_domain=SPOOK_DOMAIN,
translation_key="restart_failed",
) )
# Waited on, the way calling Home Assistant's own restart is. It # Waited on, the way calling Home Assistant's own restart is. It
@@ -7,9 +7,9 @@ from typing import TYPE_CHECKING
import voluptuous as vol import voluptuous as vol
from homeassistant.components.homeassistant import DOMAIN from homeassistant.components.homeassistant import DOMAIN
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import area_registry as ar, config_validation as cv from homeassistant.helpers import area_registry as ar, config_validation as cv
from ....errors import area_not_found
from ....services import AbstractSpookAdminService from ....services import AbstractSpookAdminService
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -30,8 +30,7 @@ class SpookService(AbstractSpookAdminService):
"""Handle the service call.""" """Handle the service call."""
area_registry = ar.async_get(self.hass) area_registry = ar.async_get(self.hass)
if not area_registry.async_get_area(call.data["area_id"]): if not area_registry.async_get_area(call.data["area_id"]):
msg = f"Area {call.data['area_id']} not found" raise area_not_found(call.data["area_id"])
raise HomeAssistantError(msg)
area_registry.async_update( area_registry.async_update(
call.data["area_id"], call.data["area_id"],
@@ -7,9 +7,9 @@ from typing import TYPE_CHECKING
import voluptuous as vol import voluptuous as vol
from homeassistant.components.homeassistant import DOMAIN from homeassistant.components.homeassistant import DOMAIN
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv, floor_registry as fr from homeassistant.helpers import config_validation as cv, floor_registry as fr
from ....errors import floor_not_found
from ....services import AbstractSpookAdminService from ....services import AbstractSpookAdminService
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -30,8 +30,7 @@ class SpookService(AbstractSpookAdminService):
"""Handle the service call.""" """Handle the service call."""
floor_registry = fr.async_get(self.hass) floor_registry = fr.async_get(self.hass)
if not floor_registry.async_get_floor(call.data["floor_id"]): if not floor_registry.async_get_floor(call.data["floor_id"]):
msg = f"Floor {call.data['floor_id']} not found" raise floor_not_found(call.data["floor_id"])
raise HomeAssistantError(msg)
floor_registry.async_update( floor_registry.async_update(
call.data["floor_id"], call.data["floor_id"],
@@ -10,6 +10,8 @@ import voluptuous as vol
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
from ....const import DOMAIN
if TYPE_CHECKING: if TYPE_CHECKING:
from homeassistant.components.input_number import InputNumber from homeassistant.components.input_number import InputNumber
from homeassistant.core import ServiceCall from homeassistant.core import ServiceCall
@@ -31,8 +33,14 @@ def native_value_as_float(entity: InputNumber) -> float:
try: try:
return float(entity.native_value) return float(entity.native_value)
except (TypeError, ValueError) as err: except (TypeError, ValueError) as err:
msg = f"Value {entity.native_value!r} for {entity.entity_id} is not a number" raise HomeAssistantError(
raise HomeAssistantError(msg) from err translation_domain=DOMAIN,
translation_key="value_not_a_number",
translation_placeholders={
"value": repr(entity.native_value),
"entity_id": entity.entity_id,
},
) from err
def step_amount(entity: InputNumber, call: ServiceCall) -> float: def step_amount(entity: InputNumber, call: ServiceCall) -> float:
@@ -6,6 +6,8 @@ from typing import TYPE_CHECKING
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from ....const import DOMAIN
if TYPE_CHECKING: if TYPE_CHECKING:
from homeassistant.components.number import NumberEntity from homeassistant.components.number import NumberEntity
@@ -21,8 +23,14 @@ def shown_value_as_float(entity: NumberEntity) -> float:
try: try:
return float(entity.value) return float(entity.value)
except (TypeError, ValueError) as err: except (TypeError, ValueError) as err:
msg = f"Value {entity.value!r} for {entity.entity_id} is not a number" raise HomeAssistantError(
raise HomeAssistantError(msg) from err translation_domain=DOMAIN,
translation_key="value_not_a_number",
translation_placeholders={
"value": repr(entity.value),
"entity_id": entity.entity_id,
},
) from err
async def async_set_shown_value(entity: NumberEntity, value: float) -> None: async def async_set_shown_value(entity: NumberEntity, value: float) -> None:
@@ -7,6 +7,7 @@ from typing import TYPE_CHECKING
from homeassistant.components.number import DOMAIN, NumberEntity from homeassistant.components.number import DOMAIN, NumberEntity
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from ....const import DOMAIN as SPOOK_DOMAIN
from ....services import AbstractSpookEntityComponentService from ....services import AbstractSpookEntityComponentService
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -26,6 +27,11 @@ class SpookService(AbstractSpookEntityComponentService[NumberEntity]):
) -> None: ) -> None:
"""Handle the service call.""" """Handle the service call."""
if entity.max_value is None: if entity.max_value is None:
msg = f"Entity {entity.entity_id} has no max value" raise HomeAssistantError(
raise HomeAssistantError(msg) translation_domain=SPOOK_DOMAIN,
translation_key="no_max_value",
translation_placeholders={
"entity_id": entity.entity_id,
},
)
await entity.async_set_native_value(entity.native_max_value) await entity.async_set_native_value(entity.native_max_value)
@@ -7,6 +7,7 @@ from typing import TYPE_CHECKING
from homeassistant.components.number import DOMAIN, NumberEntity from homeassistant.components.number import DOMAIN, NumberEntity
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from ....const import DOMAIN as SPOOK_DOMAIN
from ....services import AbstractSpookEntityComponentService from ....services import AbstractSpookEntityComponentService
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -26,6 +27,11 @@ class SpookService(AbstractSpookEntityComponentService[NumberEntity]):
) -> None: ) -> None:
"""Handle the service call.""" """Handle the service call."""
if entity.min_value is None: if entity.min_value is None:
msg = f"Entity {entity.entity_id} has no min value" raise HomeAssistantError(
raise HomeAssistantError(msg) translation_domain=SPOOK_DOMAIN,
translation_key="no_min_value",
translation_placeholders={
"entity_id": entity.entity_id,
},
)
await entity.async_set_native_value(entity.native_min_value) await entity.async_set_native_value(entity.native_min_value)
@@ -11,6 +11,8 @@ from homeassistant.components.person import DOMAIN, Person, PersonStorageCollect
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
from ....const import DOMAIN as SPOOK_DOMAIN
from ....errors import entity_not_found
from ....services import AbstractSpookAdminService from ....services import AbstractSpookAdminService
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -38,13 +40,17 @@ class SpookService(AbstractSpookAdminService):
_, collection, entity_component = self.hass.data[DOMAIN] _, collection, entity_component = self.hass.data[DOMAIN]
if not (entity := entity_component.get_entity(call.data["entity_id"])): if not (entity := entity_component.get_entity(call.data["entity_id"])):
message = f"Could not find entity_id: {call.data['entity_id']}" raise entity_not_found(call.data["entity_id"])
raise HomeAssistantError(message)
# pylint: disable-next=protected-access # pylint: disable-next=protected-access
if not entity.editable or "id" not in entity._config: # noqa: SLF001 if not entity.editable or "id" not in entity._config: # noqa: SLF001
message = f"This person is not editable: {call.data['entity_id']}" raise HomeAssistantError(
raise HomeAssistantError(message) translation_domain=SPOOK_DOMAIN,
translation_key="person_not_editable",
translation_placeholders={
"entity_id": call.data["entity_id"],
},
)
await collection.async_update_item( await collection.async_update_item(
# pylint: disable-next=protected-access # pylint: disable-next=protected-access
@@ -11,6 +11,8 @@ from homeassistant.components.person import DOMAIN, Person, PersonStorageCollect
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
from ....const import DOMAIN as SPOOK_DOMAIN
from ....errors import entity_not_found
from ....services import AbstractSpookAdminService from ....services import AbstractSpookAdminService
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -38,13 +40,17 @@ class SpookService(AbstractSpookAdminService):
_, collection, entity_component = self.hass.data[DOMAIN] _, collection, entity_component = self.hass.data[DOMAIN]
if not (entity := entity_component.get_entity(call.data["entity_id"])): if not (entity := entity_component.get_entity(call.data["entity_id"])):
message = f"Could not find entity_id: {call.data['entity_id']}" raise entity_not_found(call.data["entity_id"])
raise HomeAssistantError(message)
# pylint: disable-next=protected-access # pylint: disable-next=protected-access
if not entity.editable or "id" not in entity._config: # noqa: SLF001 if not entity.editable or "id" not in entity._config: # noqa: SLF001
message = f"This person is not editable: {call.data['entity_id']}" raise HomeAssistantError(
raise HomeAssistantError(message) translation_domain=SPOOK_DOMAIN,
translation_key="person_not_editable",
translation_placeholders={
"entity_id": call.data["entity_id"],
},
)
await collection.async_update_item( await collection.async_update_item(
# pylint: disable-next=protected-access # pylint: disable-next=protected-access
@@ -3,8 +3,8 @@
from __future__ import annotations from __future__ import annotations
from homeassistant.components import repairs from homeassistant.components import repairs
from homeassistant.const import __version__ from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
from homeassistant.helpers.device_registry import DeviceInfo from homeassistant.loader import async_get_loaded_integration
from ...const import DOMAIN from ...const import DOMAIN
from ...entity import SpookEntity, SpookEntityDescription from ...entity import SpookEntity, SpookEntityDescription
@@ -16,10 +16,21 @@ class RepairsSpookEntity(SpookEntity):
def __init__(self, description: SpookEntityDescription) -> None: def __init__(self, description: SpookEntityDescription) -> None:
"""Initialize the entity.""" """Initialize the entity."""
super().__init__(description=description) super().__init__(description=description)
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, repairs.DOMAIN)},
manufacturer="Home Assistant",
name="Repairs",
sw_version=__version__,
)
self._attr_unique_id = f"{repairs.DOMAIN}_{description.key}" self._attr_unique_id = f"{repairs.DOMAIN}_{description.key}"
@property
def device_info(self) -> DeviceInfo:
"""Return the device, which is Spook's, so it runs Spook's version.
Read once the entity is added to Home Assistant, as the version comes
from the loaded integration.
"""
version = async_get_loaded_integration(self.hass, DOMAIN).version
return DeviceInfo(
identifiers={(DOMAIN, repairs.DOMAIN)},
manufacturer="Spook 👻",
name="Repairs",
sw_version=str(version) if version else None,
configuration_url="https://spook.boo/repairs",
entry_type=DeviceEntryType.SERVICE,
)
@@ -21,5 +21,7 @@ class SpookService(AbstractSpookService):
async def async_handle_service(self, _: ServiceCall) -> None: async def async_handle_service(self, _: ServiceCall) -> None:
"""Handle the service call.""" """Handle the service call."""
msg = "Spooked!" raise HomeAssistantError(
raise HomeAssistantError(msg) translation_domain=DOMAIN,
translation_key="spooked",
)
@@ -23,5 +23,7 @@ class SpookService(AbstractSpookService):
async def async_handle_service(self, _: ServiceCall) -> None: async def async_handle_service(self, _: ServiceCall) -> None:
"""Handle the service call.""" """Handle the service call."""
if random.choice([True, False]): # noqa: S311 if random.choice([True, False]): # noqa: S311
msg = "Spooked!" raise HomeAssistantError(
raise HomeAssistantError(msg) translation_domain=DOMAIN,
translation_key="spooked",
)
@@ -17,6 +17,7 @@ from homeassistant.const import CONF_ID
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
from ....const import DOMAIN as SPOOK_DOMAIN
from ....services import AbstractSpookEntityComponentService from ....services import AbstractSpookEntityComponentService
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -45,8 +46,13 @@ class SpookService(AbstractSpookEntityComponentService[Timer]):
entity_id = entity.entity_id entity_id = entity.entity_id
if not entity.editable or not entity.unique_id: if not entity.editable or not entity.unique_id:
message = f"This timer is not editable: {entity_id}" raise HomeAssistantError(
raise HomeAssistantError(message) translation_domain=SPOOK_DOMAIN,
translation_key="timer_not_editable",
translation_placeholders={
"entity_id": entity_id,
},
)
# pylint: disable-next=protected-access # pylint: disable-next=protected-access
updates = entity._config.copy() # noqa: SLF001 updates = entity._config.copy() # noqa: SLF001
@@ -11,6 +11,8 @@ from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.entity_component import DATA_INSTANCES, EntityComponent from homeassistant.helpers.entity_component import DATA_INSTANCES, EntityComponent
from ....const import DOMAIN as SPOOK_DOMAIN
from ....errors import entity_not_found
from ....services import AbstractSpookAdminService from ....services import AbstractSpookAdminService
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -46,13 +48,17 @@ class SpookService(AbstractSpookAdminService):
zone_ids = [] zone_ids = []
for entity_id in call.data["entity_id"]: for entity_id in call.data["entity_id"]:
if not (entity := entity_component.get_entity(entity_id)): if not (entity := entity_component.get_entity(entity_id)):
message = f"Could not find entity_id: {entity_id}" raise entity_not_found(entity_id)
raise HomeAssistantError(message)
# pylint: disable-next=protected-access # pylint: disable-next=protected-access
if not entity.editable or "id" not in entity._config: # noqa: SLF001 if not entity.editable or "id" not in entity._config: # noqa: SLF001
message = f"This zone is not editable: {entity_id}" raise HomeAssistantError(
raise HomeAssistantError(message) translation_domain=SPOOK_DOMAIN,
translation_key="zone_not_editable",
translation_placeholders={
"entity_id": entity_id,
},
)
# pylint: disable-next=protected-access # pylint: disable-next=protected-access
zone_ids.append(entity._config["id"]) # noqa: SLF001 zone_ids.append(entity._config["id"]) # noqa: SLF001
@@ -18,6 +18,8 @@ from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.entity_component import DATA_INSTANCES, EntityComponent from homeassistant.helpers.entity_component import DATA_INSTANCES, EntityComponent
from ....const import DOMAIN as SPOOK_DOMAIN
from ....errors import entity_not_found
from ....services import AbstractSpookAdminService from ....services import AbstractSpookAdminService
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -65,8 +67,7 @@ class SpookService(AbstractSpookAdminService):
].__self__.storage_collection ].__self__.storage_collection
if not (entity := entity_component.get_entity(call.data["entity_id"])): if not (entity := entity_component.get_entity(call.data["entity_id"])):
message = f"Could not find entity_id: {call.data['entity_id']}" raise entity_not_found(call.data["entity_id"])
raise HomeAssistantError(message)
if _is_the_house(entity): if _is_the_house(entity):
await self._async_update_home(call) await self._async_update_home(call)
@@ -74,8 +75,13 @@ class SpookService(AbstractSpookAdminService):
# pylint: disable-next=protected-access # pylint: disable-next=protected-access
if not entity.editable or "id" not in entity._config: # noqa: SLF001 if not entity.editable or "id" not in entity._config: # noqa: SLF001
message = f"This zone is not editable: {call.data['entity_id']}" raise HomeAssistantError(
raise HomeAssistantError(message) translation_domain=SPOOK_DOMAIN,
translation_key="zone_not_editable",
translation_placeholders={
"entity_id": call.data["entity_id"],
},
)
data = call.data.copy() data = call.data.copy()
data.pop("entity_id") data.pop("entity_id")
@@ -98,11 +104,11 @@ class SpookService(AbstractSpookAdminService):
data.pop("entity_id") data.pop("entity_id")
if unsupported := set(data) - {CONF_LATITUDE, CONF_LONGITUDE, CONF_RADIUS}: if unsupported := set(data) - {CONF_LATITUDE, CONF_LONGITUDE, CONF_RADIUS}:
message = ( raise HomeAssistantError(
"The home zone only takes a latitude, longitude and radius, " translation_domain=SPOOK_DOMAIN,
f"not: {', '.join(sorted(unsupported))}" translation_key="home_zone_unsupported",
translation_placeholders={"fields": ", ".join(sorted(unsupported))},
) )
raise HomeAssistantError(message)
# Home Assistant keeps the radius of the house in whole meters, and # Home Assistant keeps the radius of the house in whole meters, and
# never below zero. Cutting a fraction off quietly would be a # never below zero. Cutting a fraction off quietly would be a
@@ -111,8 +117,10 @@ class SpookService(AbstractSpookAdminService):
if CONF_RADIUS in data: if CONF_RADIUS in data:
radius = data[CONF_RADIUS] radius = data[CONF_RADIUS]
if radius != int(radius) or radius < 0: if radius != int(radius) or radius < 0:
message = "The home zone takes its radius in whole meters, zero or more" raise HomeAssistantError(
raise HomeAssistantError(message) translation_domain=SPOOK_DOMAIN,
translation_key="home_zone_radius",
)
data[CONF_RADIUS] = int(radius) data[CONF_RADIUS] = int(radius)
await self.hass.config.async_update(**data) await self.hass.config.async_update(**data)
+52 -8
View File
@@ -6,6 +6,8 @@ from dataclasses import dataclass
import re import re
from typing import TYPE_CHECKING, Any from typing import TYPE_CHECKING, Any
import voluptuous as vol
from homeassistant.components import automation, script from homeassistant.components import automation, script
from homeassistant.const import ( from homeassistant.const import (
CONF_CHOOSE, CONF_CHOOSE,
@@ -728,11 +730,18 @@ def split_comma_separated_entity_ids(entity_id: str) -> list[str]:
@callback @callback
def async_find_services_in_sequence( # noqa: C901 def async_find_services_in_sequence( # noqa: C901
sequence: Sequence[dict[str, Any]], sequence: Sequence[dict[str, Any]],
*,
include_disabled: bool = False,
) -> set[str]: ) -> set[str]:
"""Find all services called in a sequence.""" """Find all services called in a sequence.
Steps carrying `enabled: false` are skipped unless `include_disabled` is
set: a repair cares about what runs, a search for where an action is
named cares about the step somebody may switch back on.
"""
called_services: set[str] = set() called_services: set[str] = set()
for step in sequence: for step in sequence:
if step.get(CONF_ENABLED) is False: if step.get(CONF_ENABLED) is False and not include_disabled:
continue continue
action = cv.determine_script_action(step) action = cv.determine_script_action(step)
@@ -746,25 +755,60 @@ def async_find_services_in_sequence( # noqa: C901
if action == cv.SCRIPT_ACTION_CHOOSE: if action == cv.SCRIPT_ACTION_CHOOSE:
for choice in step[CONF_CHOOSE]: for choice in step[CONF_CHOOSE]:
called_services |= async_find_services_in_sequence( called_services |= async_find_services_in_sequence(
choice[CONF_SEQUENCE] choice[CONF_SEQUENCE], include_disabled=include_disabled
) )
if nested_sequence := step.get(CONF_DEFAULT): if nested_sequence := step.get(CONF_DEFAULT):
called_services |= async_find_services_in_sequence(nested_sequence) called_services |= async_find_services_in_sequence(
nested_sequence, include_disabled=include_disabled
)
if action == cv.SCRIPT_ACTION_IF: if action == cv.SCRIPT_ACTION_IF:
called_services |= async_find_services_in_sequence(step[CONF_THEN]) called_services |= async_find_services_in_sequence(
step[CONF_THEN], include_disabled=include_disabled
)
if nested_sequence := step.get(CONF_ELSE): if nested_sequence := step.get(CONF_ELSE):
called_services |= async_find_services_in_sequence(nested_sequence) called_services |= async_find_services_in_sequence(
nested_sequence, include_disabled=include_disabled
)
if action == cv.SCRIPT_ACTION_PARALLEL: if action == cv.SCRIPT_ACTION_PARALLEL:
for nested_sequence in step[CONF_PARALLEL]: for nested_sequence in step[CONF_PARALLEL]:
called_services |= async_find_services_in_sequence( called_services |= async_find_services_in_sequence(
nested_sequence[CONF_SEQUENCE] nested_sequence[CONF_SEQUENCE], include_disabled=include_disabled
) )
if action == cv.SCRIPT_ACTION_REPEAT: if action == cv.SCRIPT_ACTION_REPEAT:
called_services |= async_find_services_in_sequence( called_services |= async_find_services_in_sequence(
step[CONF_REPEAT][CONF_SEQUENCE] step[CONF_REPEAT][CONF_SEQUENCE], include_disabled=include_disabled
) )
return called_services return called_services
def find_services_in_helper_options(
options: Mapping[str, Any], *, include_disabled: bool = False
) -> set[str]:
"""Find all services the actions in a helper's options call.
Which options hold actions grows with every new template helper type, so
ask Home Assistant instead of keeping a list of keys.
Validating is not just a shape check. The walker reads keys that only
exist after validation, so raw options make it raise on shapes the action
editor writes every day, a `parallel` block among them. Validation
normalizes those, and turns a templated action name into a Template,
which is not a string and so falls out of the known-services filter on
its own.
"""
services: set[str] = set()
for option in options.values():
try:
sequence = cv.SCRIPT_SCHEMA(option)
except vol.Invalid:
continue
services.update(
async_find_services_in_sequence(sequence, include_disabled=include_disabled)
)
return services
+389
View File
@@ -1,5 +1,8 @@
{ {
"conditions": { "conditions": {
"is_available": {
"condition": "mdi:lan-connect"
},
"is_at_target_temperature": { "is_at_target_temperature": {
"condition": "mdi:thermometer-check" "condition": "mdi:thermometer-check"
}, },
@@ -91,6 +94,392 @@
}, },
"user_added": { "user_added": {
"trigger": "mdi:account-plus" "trigger": "mdi:account-plus"
},
"state_changed": {
"trigger": "mdi:ghost-outline"
}
},
"services": {
"automation_snooze": {
"service": "mdi:sleep"
},
"automation_turn_on_for": {
"service": "mdi:timer-play"
},
"blueprint_import": {
"service": "mdi:file-import"
},
"boo": {
"service": "mdi:ghost"
},
"calendar_delete_event": {
"service": "mdi:calendar-remove"
},
"calendar_update_event": {
"service": "mdi:calendar-edit"
},
"climate_decrease_temperature": {
"service": "mdi:thermometer-minus"
},
"climate_increase_temperature": {
"service": "mdi:thermometer-plus"
},
"counter_create": {
"service": "mdi:counter"
},
"counter_delete": {
"service": "mdi:delete"
},
"cover_decrease_position": {
"service": "mdi:arrow-down-box"
},
"cover_increase_position": {
"service": "mdi:arrow-up-box"
},
"group_add_members": {
"service": "mdi:playlist-plus"
},
"group_remove_members": {
"service": "mdi:playlist-minus"
},
"group_set_members": {
"service": "mdi:playlist-edit"
},
"homeassistant_add_alias_to_area": {
"service": "mdi:text-box-plus"
},
"homeassistant_add_alias_to_entity": {
"service": "mdi:text-box-plus"
},
"homeassistant_add_alias_to_floor": {
"service": "mdi:text-box-plus"
},
"homeassistant_add_area_to_floor": {
"service": "mdi:layers-plus"
},
"homeassistant_add_category_to_entity": {
"service": "mdi:shape-plus"
},
"homeassistant_add_device_to_area": {
"service": "mdi:home-plus"
},
"homeassistant_add_entity_to_area": {
"service": "mdi:home-plus"
},
"homeassistant_add_label_to_area": {
"service": "mdi:tag-plus"
},
"homeassistant_add_label_to_device": {
"service": "mdi:tag-plus"
},
"homeassistant_add_label_to_entity": {
"service": "mdi:tag-plus"
},
"homeassistant_create_area": {
"service": "mdi:home-plus"
},
"homeassistant_create_category": {
"service": "mdi:shape-plus"
},
"homeassistant_create_floor": {
"service": "mdi:layers-plus"
},
"homeassistant_create_label": {
"service": "mdi:tag-plus"
},
"homeassistant_delete_all_orphaned_entities": {
"service": "mdi:delete-sweep"
},
"homeassistant_delete_area": {
"service": "mdi:home-minus"
},
"homeassistant_delete_category": {
"service": "mdi:shape"
},
"homeassistant_delete_floor": {
"service": "mdi:layers-minus"
},
"homeassistant_delete_label": {
"service": "mdi:tag-minus"
},
"homeassistant_disable_config_entry": {
"service": "mdi:puzzle-remove"
},
"homeassistant_disable_device": {
"service": "mdi:cancel"
},
"homeassistant_disable_entity": {
"service": "mdi:cancel"
},
"homeassistant_disable_polling": {
"service": "mdi:sync-off"
},
"homeassistant_disable_user": {
"service": "mdi:account-off"
},
"homeassistant_enable_config_entry": {
"service": "mdi:puzzle-check"
},
"homeassistant_enable_device": {
"service": "mdi:check-circle"
},
"homeassistant_enable_entity": {
"service": "mdi:check-circle"
},
"homeassistant_enable_polling": {
"service": "mdi:sync"
},
"homeassistant_enable_user": {
"service": "mdi:account-check"
},
"homeassistant_expose_entity": {
"service": "mdi:microphone-message"
},
"homeassistant_hide_entity": {
"service": "mdi:eye-off"
},
"homeassistant_ignore_all_discovered": {
"service": "mdi:magnify-scan"
},
"homeassistant_list_orphaned_database_entities": {
"service": "mdi:database-search"
},
"homeassistant_remove_alias_from_area": {
"service": "mdi:text-box-minus"
},
"homeassistant_remove_alias_from_entity": {
"service": "mdi:text-box-minus"
},
"homeassistant_remove_alias_from_floor": {
"service": "mdi:text-box-minus"
},
"homeassistant_remove_area_from_floor": {
"service": "mdi:layers-minus"
},
"homeassistant_remove_category_from_entity": {
"service": "mdi:shape"
},
"homeassistant_remove_device_from_area": {
"service": "mdi:home-minus"
},
"homeassistant_remove_entity_from_area": {
"service": "mdi:home-minus"
},
"homeassistant_remove_label_from_area": {
"service": "mdi:tag-minus"
},
"homeassistant_remove_label_from_device": {
"service": "mdi:tag-minus"
},
"homeassistant_remove_label_from_entity": {
"service": "mdi:tag-minus"
},
"homeassistant_rename_entity": {
"service": "mdi:rename-box"
},
"homeassistant_restart": {
"service": "mdi:restart"
},
"homeassistant_set_area_aliases": {
"service": "mdi:text-box-edit"
},
"homeassistant_set_entity_aliases": {
"service": "mdi:text-box-edit"
},
"homeassistant_set_entity_icon": {
"service": "mdi:emoticon-outline"
},
"homeassistant_set_floor_aliases": {
"service": "mdi:text-box-edit"
},
"homeassistant_unexpose_entity": {
"service": "mdi:microphone-message-off"
},
"homeassistant_unhide_entity": {
"service": "mdi:eye"
},
"homeassistant_update_category": {
"service": "mdi:shape-outline"
},
"homeassistant_update_entity_id": {
"service": "mdi:identifier"
},
"homeassistant_update_label": {
"service": "mdi:tag-edit"
},
"humidifier_decrease_humidity": {
"service": "mdi:water-minus"
},
"humidifier_increase_humidity": {
"service": "mdi:water-plus"
},
"input_boolean_create": {
"service": "mdi:toggle-switch-outline"
},
"input_boolean_delete": {
"service": "mdi:delete"
},
"input_button_create": {
"service": "mdi:gesture-tap-button"
},
"input_button_delete": {
"service": "mdi:delete"
},
"input_datetime_create": {
"service": "mdi:calendar-clock"
},
"input_datetime_delete": {
"service": "mdi:delete"
},
"input_number_create": {
"service": "mdi:numeric"
},
"input_number_decrement": {
"service": "mdi:minus-box"
},
"input_number_delete": {
"service": "mdi:delete"
},
"input_number_increment": {
"service": "mdi:plus-box"
},
"input_number_max": {
"service": "mdi:arrow-collapse-up"
},
"input_number_min": {
"service": "mdi:arrow-collapse-down"
},
"input_number_set_range": {
"service": "mdi:arrow-expand-horizontal"
},
"input_select_create": {
"service": "mdi:form-select"
},
"input_select_delete": {
"service": "mdi:delete"
},
"input_select_random": {
"service": "mdi:dice-multiple"
},
"input_select_reverse": {
"service": "mdi:swap-vertical"
},
"input_select_shuffle": {
"service": "mdi:shuffle-variant"
},
"input_select_sort": {
"service": "mdi:sort-alphabetical-ascending"
},
"input_text_create": {
"service": "mdi:form-textbox"
},
"input_text_delete": {
"service": "mdi:delete"
},
"light_decrease_brightness": {
"service": "mdi:brightness-5"
},
"light_increase_brightness": {
"service": "mdi:brightness-7"
},
"light_set_brightness": {
"service": "mdi:brightness-6"
},
"light_set_color": {
"service": "mdi:palette"
},
"light_set_color_temperature": {
"service": "mdi:thermometer"
},
"light_set_effect": {
"service": "mdi:auto-fix"
},
"media_player_decrease_volume": {
"service": "mdi:volume-minus"
},
"media_player_increase_volume": {
"service": "mdi:volume-plus"
},
"number_decrement": {
"service": "mdi:minus-box"
},
"number_increment": {
"service": "mdi:plus-box"
},
"number_max": {
"service": "mdi:arrow-collapse-up"
},
"number_min": {
"service": "mdi:arrow-collapse-down"
},
"person_add_device_tracker": {
"service": "mdi:account-plus"
},
"person_remove_device_tracker": {
"service": "mdi:account-minus"
},
"random_fail": {
"service": "mdi:dice-5"
},
"recorder_import_statistics": {
"service": "mdi:chart-box-plus-outline"
},
"repairs_create": {
"service": "mdi:alert-plus"
},
"repairs_ignore_all": {
"service": "mdi:checkbox-multiple-blank-outline"
},
"repairs_list": {
"service": "mdi:format-list-bulleted"
},
"repairs_remove": {
"service": "mdi:alert-minus"
},
"repairs_unignore_all": {
"service": "mdi:checkbox-multiple-marked"
},
"select_random": {
"service": "mdi:dice-multiple"
},
"sensor_set_display_precision": {
"service": "mdi:decimal"
},
"timer_create": {
"service": "mdi:timer-plus"
},
"timer_delete": {
"service": "mdi:timer-remove"
},
"timer_set_duration": {
"service": "mdi:timer-edit"
},
"todo_move_item": {
"service": "mdi:swap-vertical-bold"
},
"valve_decrease_position": {
"service": "mdi:arrow-down-box"
},
"valve_increase_position": {
"service": "mdi:arrow-up-box"
},
"wait_for_condition": {
"service": "mdi:timer-sand"
},
"water_heater_decrease_temperature": {
"service": "mdi:thermometer-minus"
},
"water_heater_increase_temperature": {
"service": "mdi:thermometer-plus"
},
"zone_create": {
"service": "mdi:map-marker-plus"
},
"zone_delete": {
"service": "mdi:map-marker-remove"
},
"zone_update": {
"service": "mdi:map-marker-radius"
} }
} }
} }
+21 -5
View File
@@ -11,11 +11,11 @@ if TYPE_CHECKING:
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
def link_sub_integrations(hass: HomeAssistant) -> bool: def link_sub_integrations(hass: HomeAssistant) -> set[str]:
"""Link Spook sub integrations.""" """Link Spook sub integrations, and return the ones newly linked."""
LOGGER.debug("Linking up Spook sub integrations") LOGGER.debug("Linking up Spook sub integrations")
changes = False linked: set[str] = set()
for manifest in Path(__file__).parent.rglob("integrations/*/manifest.json"): for manifest in Path(__file__).parent.rglob("integrations/*/manifest.json"):
LOGGER.debug("Linking Spook sub integration: %s", manifest.parent.name) LOGGER.debug("Linking Spook sub integration: %s", manifest.parent.name)
dest = Path(hass.config.config_dir) / "custom_components" / manifest.parent.name dest = Path(hass.config.config_dir) / "custom_components" / manifest.parent.name
@@ -28,8 +28,8 @@ def link_sub_integrations(hass: HomeAssistant) -> bool:
/ manifest.parent.name / manifest.parent.name
) )
dest.symlink_to(src) dest.symlink_to(src)
changes = True linked.add(manifest.parent.name)
return changes return linked
def unlink_sub_integrations(hass: HomeAssistant) -> None: def unlink_sub_integrations(hass: HomeAssistant) -> None:
@@ -40,3 +40,19 @@ def unlink_sub_integrations(hass: HomeAssistant) -> None:
dest = Path(hass.config.config_dir) / "custom_components" / manifest.parent.name dest = Path(hass.config.config_dir) / "custom_components" / manifest.parent.name
if dest.exists(): if dest.exists():
dest.unlink() dest.unlink()
def sub_integration_links(hass: HomeAssistant) -> dict[str, bool]:
"""Return each Spook sub integration, and whether it is linked.
Linked means a symlink that leads to Spook's own copy. A folder or a
link to somewhere else with the same name loads other code, or none.
"""
custom_components = Path(hass.config.config_dir) / "custom_components"
links: dict[str, bool] = {}
for manifest in sorted(Path(__file__).parent.rglob("integrations/*/manifest.json")):
link = custom_components / manifest.parent.name
links[manifest.parent.name] = (
link.is_symlink() and link.resolve() == manifest.parent.resolve()
)
return links
@@ -10,5 +10,5 @@
"iot_class": "calculated", "iot_class": "calculated",
"issue_tracker": "https://github.com/frenck/spook/issues", "issue_tracker": "https://github.com/frenck/spook/issues",
"requirements": [], "requirements": [],
"version": "5.9.0" "version": "5.10.0"
} }
@@ -1 +1,37 @@
{} {
"config": {
"step": {
"user": {
"data": {
"entity_id": "Entitat d'origen",
"name": "Nom",
"offset": "Desplaçament",
"factor": "Factor"
},
"data_description": {
"offset": "S'afegeix al valor de l'origen. Un sensor que marca 1,5 graus de més rep -1,5. En la unitat en què informa l'origen.",
"factor": "Primer es multiplica el valor de l'origen per aquest. Deixa'l a 1 per només afegir el desplaçament."
},
"description": "Aquest ajudant corregeix un sensor que no marca bé: una temperatura un grau massa alta, una humitat uns quants per cent massa baixa. Mostra el valor de l'origen multiplicat pel factor, més el desplaçament.",
"title": "Calibratge 👻"
}
}
},
"options": {
"step": {
"init": {
"data": {
"entity_id": "Entitat d'origen",
"offset": "Desplaçament",
"factor": "Factor"
},
"data_description": {
"offset": "S'afegeix al valor de l'origen. Un sensor que marca 1,5 graus de més rep -1,5. En la unitat en què informa l'origen.",
"factor": "Primer es multiplica el valor de l'origen per aquest. Deixa'l a 1 per només afegir el desplaçament."
},
"title": "Calibratge 👻"
}
}
},
"title": "Calibratge 👻"
}
@@ -1 +1,37 @@
{} {
"config": {
"step": {
"user": {
"data": {
"entity_id": "Zdrojová entita",
"name": "Název",
"offset": "Posun",
"factor": "Koeficient"
},
"data_description": {
"offset": "Přičte se k hodnotě zdroje. Senzor, který ukazuje o 1,5 stupně víc, dostane -1,5. V jednotce, ve které zdroj hlásí.",
"factor": "Hodnota zdroje se nejdřív vynásobí tímto číslem. Ponechte 1, pokud chcete jen přičíst posun."
},
"description": "Tento pomocník opravuje senzor, který měří vedle: teplotu o stupeň vyšší, vlhkost o pár procent nižší. Zobrazuje hodnotu zdroje vynásobenou koeficientem, plus posun.",
"title": "Kalibrace 👻"
}
}
},
"options": {
"step": {
"init": {
"data": {
"entity_id": "Zdrojová entita",
"offset": "Posun",
"factor": "Koeficient"
},
"data_description": {
"offset": "Přičte se k hodnotě zdroje. Senzor, který ukazuje o 1,5 stupně víc, dostane -1,5. V jednotce, ve které zdroj hlásí.",
"factor": "Hodnota zdroje se nejdřív vynásobí tímto číslem. Ponechte 1, pokud chcete jen přičíst posun."
},
"title": "Kalibrace 👻"
}
}
},
"title": "Kalibrace 👻"
}
@@ -1 +1,37 @@
{} {
"config": {
"step": {
"user": {
"data": {
"entity_id": "Kildeentitet",
"name": "Navn",
"offset": "Forskydning",
"factor": "Faktor"
},
"data_description": {
"offset": "Lægges til kildens værdi. En sensor, der viser 1,5 grader for meget, får -1,5. I den måleenhed, kilden bruger.",
"factor": "Kildens værdi ganges først med denne. Lad den stå på 1 for kun at lægge forskydningen til."
},
"description": "Denne hjælper retter en sensor, der viser forkert: en temperatur en grad for høj, en luftfugtighed et par procent for lav. Den viser kildens værdi gange faktoren plus forskydningen.",
"title": "Kalibrering 👻"
}
}
},
"options": {
"step": {
"init": {
"data": {
"entity_id": "Kildeentitet",
"offset": "Forskydning",
"factor": "Faktor"
},
"data_description": {
"offset": "Lægges til kildens værdi. En sensor, der viser 1,5 grader for meget, får -1,5. I den måleenhed, kilden bruger.",
"factor": "Kildens værdi ganges først med denne. Lad den stå på 1 for kun at lægge forskydningen til."
},
"title": "Kalibrering 👻"
}
}
},
"title": "Kalibrering 👻"
}
@@ -1 +1,37 @@
{} {
"config": {
"step": {
"user": {
"data": {
"entity_id": "Οντότητα πηγής",
"name": "Όνομα",
"offset": "Μετατόπιση",
"factor": "Συντελεστής"
},
"data_description": {
"offset": "Προστίθεται στην τιμή της πηγής. Ένας αισθητήρας που δείχνει 1,5 βαθμό παραπάνω παίρνει -1,5. Στη μονάδα στην οποία αναφέρει η πηγή.",
"factor": "Η τιμή της πηγής πολλαπλασιάζεται πρώτα με αυτόν. Αφήστε το στο 1 για να προστεθεί μόνο η μετατόπιση."
},
"description": "Αυτός ο βοηθός διορθώνει έναν αισθητήρα που δείχνει λάθος: μια θερμοκρασία έναν βαθμό πιο ψηλά, μια υγρασία λίγες ποσοστιαίες μονάδες πιο χαμηλά. Δείχνει την τιμή της πηγής επί τον συντελεστή, συν τη μετατόπιση.",
"title": "Βαθμονόμηση 👻"
}
}
},
"options": {
"step": {
"init": {
"data": {
"entity_id": "Οντότητα πηγής",
"offset": "Μετατόπιση",
"factor": "Συντελεστής"
},
"data_description": {
"offset": "Προστίθεται στην τιμή της πηγής. Ένας αισθητήρας που δείχνει 1,5 βαθμό παραπάνω παίρνει -1,5. Στη μονάδα στην οποία αναφέρει η πηγή.",
"factor": "Η τιμή της πηγής πολλαπλασιάζεται πρώτα με αυτόν. Αφήστε το στο 1 για να προστεθεί μόνο η μετατόπιση."
},
"title": "Βαθμονόμηση 👻"
}
}
},
"title": "Βαθμονόμηση 👻"
}
@@ -1 +1,37 @@
{} {
"config": {
"step": {
"user": {
"data": {
"entity_id": "Source entity",
"name": "Name",
"offset": "Offset",
"factor": "Factor"
},
"data_description": {
"offset": "Added to the source's value. A sensor reading 1.5 degrees too high gets -1.5. In the unit the source reports in.",
"factor": "The source's value is multiplied by this first. Leave at 1 to only add the offset."
},
"description": "This helper corrects a sensor that reads off: a temperature a degree too high, a humidity a few percent too low. It shows the source's value times the factor, plus the offset.",
"title": "Calibration 👻"
}
}
},
"options": {
"step": {
"init": {
"data": {
"entity_id": "Source entity",
"offset": "Offset",
"factor": "Factor"
},
"data_description": {
"offset": "Added to the source's value. A sensor reading 1.5 degrees too high gets -1.5. In the unit the source reports in.",
"factor": "The source's value is multiplied by this first. Leave at 1 to only add the offset."
},
"title": "Calibration 👻"
}
}
},
"title": "Calibration 👻"
}
@@ -3,7 +3,7 @@
"step": { "step": {
"user": { "user": {
"data": { "data": {
"entity_id": "Entidad origen", "entity_id": "Entidad de origen",
"name": "Nombre", "name": "Nombre",
"offset": "Desplazamiento", "offset": "Desplazamiento",
"factor": "Factor" "factor": "Factor"
@@ -21,7 +21,7 @@
"step": { "step": {
"init": { "init": {
"data": { "data": {
"entity_id": "Entidad origen", "entity_id": "Entidad de origen",
"offset": "Desplazamiento", "offset": "Desplazamiento",
"factor": "Factor" "factor": "Factor"
}, },
@@ -1 +1,37 @@
{} {
"config": {
"step": {
"user": {
"data": {
"entity_id": "Entidad de origen",
"name": "Nombre",
"offset": "Desplazamiento",
"factor": "Factor"
},
"data_description": {
"offset": "Se suma al valor del origen. Un sensor que mide 1,5 grados de más recibe -1,5. En la unidad en la que informa el origen.",
"factor": "El valor del origen se multiplica primero por este número. Déjalo en 1 para solo sumar el desplazamiento."
},
"description": "Este ayudante corrige un sensor que no mide bien: una temperatura un grado demasiado alta, una humedad unos puntos demasiado baja. Muestra el valor del origen multiplicado por el factor, más el desplazamiento.",
"title": "Calibración 👻"
}
}
},
"options": {
"step": {
"init": {
"data": {
"entity_id": "Entidad de origen",
"offset": "Desplazamiento",
"factor": "Factor"
},
"data_description": {
"offset": "Se suma al valor del origen. Un sensor que mide 1,5 grados de más recibe -1,5. En la unidad en la que informa el origen.",
"factor": "El valor del origen se multiplica primero por este número. Déjalo en 1 para solo sumar el desplazamiento."
},
"title": "Calibración 👻"
}
}
},
"title": "Calibración 👻"
}
@@ -1 +1,37 @@
{} {
"config": {
"step": {
"user": {
"data": {
"entity_id": "Lähteolem",
"name": "Nimi",
"offset": "Nihe",
"factor": "Tegur"
},
"data_description": {
"offset": "Liidetakse allika väärtusele. Andur, mis näitab 1,5 kraadi liiga palju, saab -1,5. Allika enda mõõtühikus.",
"factor": "Allika väärtus korrutatakse kõigepealt sellega. Jäta 1, et lisada ainult nihe."
},
"description": "See abiline parandab andurit, mis näitab valesti: temperatuur kraadi võrra liiga kõrge, niiskus mõne protsendi võrra liiga madal. See näitab allika väärtust korrutatuna teguriga, millele on liidetud nihe.",
"title": "Kalibreerimine 👻"
}
}
},
"options": {
"step": {
"init": {
"data": {
"entity_id": "Lähteolem",
"offset": "Nihe",
"factor": "Tegur"
},
"data_description": {
"offset": "Liidetakse allika väärtusele. Andur, mis näitab 1,5 kraadi liiga palju, saab -1,5. Allika enda mõõtühikus.",
"factor": "Allika väärtus korrutatakse kõigepealt sellega. Jäta 1, et lisada ainult nihe."
},
"title": "Kalibreerimine 👻"
}
}
},
"title": "Kalibreerimine 👻"
}
@@ -1 +1,37 @@
{} {
"config": {
"step": {
"user": {
"data": {
"entity_id": "Iturburu-entitatea",
"name": "Izena",
"offset": "Desplazamendua",
"factor": "Faktorea"
},
"data_description": {
"offset": "Iturburuaren balioari gehitzen zaio. 1,5 gradu gehiegi neurtzen duen sentsore batek -1,5 jasotzen du. Iturburuak erabiltzen duen unitatean.",
"factor": "Iturburuaren balioa lehenik honekin biderkatzen da. Utzi 1ean desplazamendua soilik gehitzeko."
},
"description": "Laguntzaile honek gaizki neurtzen duen sentsore bat zuzentzen du: gradu bat altuegia den tenperatura bat, ehuneko batzuk baxuegia den hezetasun bat. Iturburuaren balioa faktorearekin biderkatuta erakusten du, gehi desplazamendua.",
"title": "Kalibrazioa 👻"
}
}
},
"options": {
"step": {
"init": {
"data": {
"entity_id": "Iturburu-entitatea",
"offset": "Desplazamendua",
"factor": "Faktorea"
},
"data_description": {
"offset": "Iturburuaren balioari gehitzen zaio. 1,5 gradu gehiegi neurtzen duen sentsore batek -1,5 jasotzen du. Iturburuak erabiltzen duen unitatean.",
"factor": "Iturburuaren balioa lehenik honekin biderkatzen da. Utzi 1ean desplazamendua soilik gehitzeko."
},
"title": "Kalibrazioa 👻"
}
}
},
"title": "Kalibrazioa 👻"
}
@@ -1 +1,37 @@
{} {
"config": {
"step": {
"user": {
"data": {
"entity_id": "Lähde-entiteetti",
"name": "Nimi",
"offset": "Korjausarvo",
"factor": "Kerroin"
},
"data_description": {
"offset": "Lisätään lähteen arvoon. Sensori, joka näyttää 1,5 astetta liikaa, saa arvon -1,5. Lähteen käyttämässä yksikössä.",
"factor": "Lähteen arvo kerrotaan ensin tällä. Jätä arvoksi 1, jos haluat vain lisätä korjausarvon."
},
"description": "Tämä apuri korjaa sensorin, joka näyttää väärin: lämpötilan, joka on asteen liian korkea, tai kosteuden, joka on muutaman prosentin liian matala. Se näyttää lähteen arvon kerrottuna kertoimella, plus korjausarvon.",
"title": "Kalibrointi 👻"
}
}
},
"options": {
"step": {
"init": {
"data": {
"entity_id": "Lähde-entiteetti",
"offset": "Korjausarvo",
"factor": "Kerroin"
},
"data_description": {
"offset": "Lisätään lähteen arvoon. Sensori, joka näyttää 1,5 astetta liikaa, saa arvon -1,5. Lähteen käyttämässä yksikössä.",
"factor": "Lähteen arvo kerrotaan ensin tällä. Jätä arvoksi 1, jos haluat vain lisätä korjausarvon."
},
"title": "Kalibrointi 👻"
}
}
},
"title": "Kalibrointi 👻"
}
@@ -3,16 +3,16 @@
"step": { "step": {
"user": { "user": {
"data": { "data": {
"entity_id": "Entité d'origine", "entity_id": "Entité source",
"name": "Nom", "name": "Nom",
"offset": "Décalage", "offset": "Décalage",
"factor": "Facteur" "factor": "Facteur"
}, },
"data_description": { "data_description": {
"offset": "Ajouté à la valeur de l'entité d'origine. Un capteur qui mesure 1,5 degré de trop reçoit -1,5. Dans l'unité de l'entité d'origine.", "offset": "Ajouté à la valeur de l'entité source. Un capteur qui mesure 1,5 degré de trop reçoit -1,5. Dans l'unité de l'entité source.",
"factor": "La valeur de l'entité d'origine est d'abord multipliée par ce facteur. Laisser à 1 pour n'ajouter que le décalage." "factor": "La valeur de l'entité source est d'abord multipliée par ce facteur. Laisser à 1 pour n'ajouter que le décalage."
}, },
"description": "Cette entrée corrige un capteur qui se trompe, comme une température trop haute d'un degré ou une humidité trop basse de quelques pour cent. Elle affiche la valeur de l'entité d'origine multipliée par le facteur, plus le décalage.", "description": "Cette entrée corrige un capteur qui se trompe, comme une température trop haute d'un degré ou une humidité trop basse de quelques pour cent. Elle affiche la valeur de l'entité source multipliée par le facteur, plus le décalage.",
"title": "Étalonnage 👻" "title": "Étalonnage 👻"
} }
} }
@@ -21,13 +21,13 @@
"step": { "step": {
"init": { "init": {
"data": { "data": {
"entity_id": "Entité d'origine", "entity_id": "Entité source",
"offset": "Décalage", "offset": "Décalage",
"factor": "Facteur" "factor": "Facteur"
}, },
"data_description": { "data_description": {
"offset": "Ajouté à la valeur de l'entité d'origine. Un capteur qui mesure 1,5 degré de trop reçoit -1,5. Dans l'unité de l'entité d'origine.", "offset": "Ajouté à la valeur de l'entité source. Un capteur qui mesure 1,5 degré de trop reçoit -1,5. Dans l'unité de l'entité source.",
"factor": "La valeur de l'entité d'origine est d'abord multipliée par ce facteur. Laisser à 1 pour n'ajouter que le décalage." "factor": "La valeur de l'entité source est d'abord multipliée par ce facteur. Laisser à 1 pour n'ajouter que le décalage."
}, },
"title": "Étalonnage 👻" "title": "Étalonnage 👻"
} }
@@ -1 +1,37 @@
{} {
"config": {
"step": {
"user": {
"data": {
"entity_id": "Boarne-entiteit",
"name": "Namme",
"offset": "Ferskowing",
"factor": "Faktor"
},
"data_description": {
"offset": "Wurdt by de wearde fan de boarne opteld. In sensor dy't 1,5 graad te heech mjit, krijt -1,5. Yn de ienheid dêr't de boarne yn rapportearret.",
"factor": "De wearde fan de boarne wurdt earst hjirmei fermannichfâldige. Lit op 1 stean om allinnich de ferskowing ta te foegjen."
},
"description": "Dizze helper korrigearret in sensor dy't der neist sit: in temperatuer in graad te heech, in fochtigens in pear persint te leech. Hy toant de wearde fan de boarne kear de faktor, plus de ferskowing.",
"title": "Kalibraasje 👻"
}
}
},
"options": {
"step": {
"init": {
"data": {
"entity_id": "Boarne-entiteit",
"offset": "Ferskowing",
"factor": "Faktor"
},
"data_description": {
"offset": "Wurdt by de wearde fan de boarne opteld. In sensor dy't 1,5 graad te heech mjit, krijt -1,5. Yn de ienheid dêr't de boarne yn rapportearret.",
"factor": "De wearde fan de boarne wurdt earst hjirmei fermannichfâldige. Lit op 1 stean om allinnich de ferskowing ta te foegjen."
},
"title": "Kalibraasje 👻"
}
}
},
"title": "Kalibraasje 👻"
}
@@ -1 +1,37 @@
{} {
"config": {
"step": {
"user": {
"data": {
"entity_id": "Aonán foinse",
"name": "Ainm",
"offset": "Fritháireamh",
"factor": "Fachtóir"
},
"data_description": {
"offset": "Cuirtear le luach na foinse é. Faigheann braiteoir a léann 1.5 céim ró-ard -1.5. San aonad ina dtuairiscíonn an fhoinse.",
"factor": "Méadaítear luach na foinse faoi seo ar dtús. Fág ag 1 é chun an fritháireamh amháin a chur leis."
},
"description": "Ceartaíonn an cúntóir seo braiteoir nach léann i gceart: teocht céim ró-ard, taiseachas cúpla faoin gcéad ró-íseal. Taispeánann sé luach na foinse méadaithe faoin bhfachtóir, móide an fritháireamh.",
"title": "Calabrú 👻"
}
}
},
"options": {
"step": {
"init": {
"data": {
"entity_id": "Aonán foinse",
"offset": "Fritháireamh",
"factor": "Fachtóir"
},
"data_description": {
"offset": "Cuirtear le luach na foinse é. Faigheann braiteoir a léann 1.5 céim ró-ard -1.5. San aonad ina dtuairiscíonn an fhoinse.",
"factor": "Méadaítear luach na foinse faoi seo ar dtús. Fág ag 1 é chun an fritháireamh amháin a chur leis."
},
"title": "Calabrú 👻"
}
}
},
"title": "Calabrú 👻"
}
@@ -1 +1,37 @@
{} {
"config": {
"step": {
"user": {
"data": {
"entity_id": "ישות מקור",
"name": "שם",
"offset": "היסט",
"factor": "מקדם"
},
"data_description": {
"offset": "מתווסף לערך של המקור. חיישן שמראה 1.5 מעלות יותר מדי מקבל -1.5. ביחידה שבה המקור מדווח.",
"factor": "ערך המקור מוכפל קודם בזה. השאר על 1 כדי להוסיף רק את ההיסט."
},
"description": "עוזר זה מתקן חיישן שמודד לא נכון: טמפרטורה גבוהה במעלה אחת, לחות נמוכה בכמה אחוזים. הוא מציג את ערך המקור כפול המקדם, ועוד ההיסט.",
"title": "כיול 👻"
}
}
},
"options": {
"step": {
"init": {
"data": {
"entity_id": "ישות מקור",
"offset": "היסט",
"factor": "מקדם"
},
"data_description": {
"offset": "מתווסף לערך של המקור. חיישן שמראה 1.5 מעלות יותר מדי מקבל -1.5. ביחידה שבה המקור מדווח.",
"factor": "ערך המקור מוכפל קודם בזה. השאר על 1 כדי להוסיף רק את ההיסט."
},
"title": "כיול 👻"
}
}
},
"title": "כיול 👻"
}
@@ -1 +1,37 @@
{} {
"config": {
"step": {
"user": {
"data": {
"entity_id": "Entitas sumber",
"name": "Nama",
"offset": "Selisih",
"factor": "Faktor"
},
"data_description": {
"offset": "Ditambahkan ke nilai sumber. Sensor yang membaca 1,5 derajat terlalu tinggi diberi -1,5. Dalam satuan yang dilaporkan sumber.",
"factor": "Nilai sumber dikalikan dengan ini terlebih dahulu. Biarkan 1 untuk hanya menambahkan selisih."
},
"description": "Pembantu ini mengoreksi sensor yang pembacaannya meleset: suhu satu derajat terlalu tinggi, kelembaban beberapa persen terlalu rendah. Pembantu ini menampilkan nilai sumber dikali faktor, ditambah selisih.",
"title": "Kalibrasi 👻"
}
}
},
"options": {
"step": {
"init": {
"data": {
"entity_id": "Entitas sumber",
"offset": "Selisih",
"factor": "Faktor"
},
"data_description": {
"offset": "Ditambahkan ke nilai sumber. Sensor yang membaca 1,5 derajat terlalu tinggi diberi -1,5. Dalam satuan yang dilaporkan sumber.",
"factor": "Nilai sumber dikalikan dengan ini terlebih dahulu. Biarkan 1 untuk hanya menambahkan selisih."
},
"title": "Kalibrasi 👻"
}
}
},
"title": "Kalibrasi 👻"
}
@@ -1 +1,37 @@
{} {
"config": {
"step": {
"user": {
"data": {
"entity_id": "Entità sorgente",
"name": "Nome",
"offset": "Scostamento",
"factor": "Fattore"
},
"data_description": {
"offset": "Viene sommato al valore della sorgente. Un sensore che segna 1,5 gradi in più riceve -1,5. Nell'unità in cui la sorgente riporta il valore.",
"factor": "Il valore della sorgente viene prima moltiplicato per questo. Lascia 1 per aggiungere solo lo scostamento."
},
"description": "Questo helper corregge un sensore che sbaglia: una temperatura di un grado troppo alta, un'umidità di qualche punto percentuale troppo bassa. Mostra il valore della sorgente moltiplicato per il fattore, più lo scostamento.",
"title": "Calibrazione 👻"
}
}
},
"options": {
"step": {
"init": {
"data": {
"entity_id": "Entità sorgente",
"offset": "Scostamento",
"factor": "Fattore"
},
"data_description": {
"offset": "Viene sommato al valore della sorgente. Un sensore che segna 1,5 gradi in più riceve -1,5. Nell'unità in cui la sorgente riporta il valore.",
"factor": "Il valore della sorgente viene prima moltiplicato per questo. Lascia 1 per aggiungere solo lo scostamento."
},
"title": "Calibrazione 👻"
}
}
},
"title": "Calibrazione 👻"
}
@@ -1 +1,37 @@
{} {
"config": {
"step": {
"user": {
"data": {
"entity_id": "ソースエンティティ",
"name": "名前",
"offset": "オフセット",
"factor": "係数"
},
"data_description": {
"offset": "ソースの値に加算されます。1.5 度高く表示されるセンサーなら -1.5 にします。単位はソースが報告する単位です。",
"factor": "ソースの値には、まずこの値が掛けられます。オフセットだけを加えるなら 1 のままにしてください。"
},
"description": "このヘルパーは、ずれた値を示すセンサーを補正します。1 度高い温度や、数パーセント低い湿度などです。ソースの値に係数を掛け、オフセットを足した値を表示します。",
"title": "キャリブレーション 👻"
}
}
},
"options": {
"step": {
"init": {
"data": {
"entity_id": "ソースエンティティ",
"offset": "オフセット",
"factor": "係数"
},
"data_description": {
"offset": "ソースの値に加算されます。1.5 度高く表示されるセンサーなら -1.5 にします。単位はソースが報告する単位です。",
"factor": "ソースの値には、まずこの値が掛けられます。オフセットだけを加えるなら 1 のままにしてください。"
},
"title": "キャリブレーション 👻"
}
}
},
"title": "キャリブレーション 👻"
}
@@ -1 +1,37 @@
{} {
"config": {
"step": {
"user": {
"data": {
"entity_id": "소스 엔티티",
"name": "이름",
"offset": "오프셋",
"factor": "배율"
},
"data_description": {
"offset": "소스 값에 더해집니다. 1.5도 높게 측정하는 센서라면 -1.5를 입력합니다. 단위는 소스가 보고하는 단위입니다.",
"factor": "소스 값에 먼저 이 값을 곱합니다. 오프셋만 더하려면 1로 두세요."
},
"description": "이 도우미는 값이 어긋나는 센서를 보정합니다. 1도 높게 나오는 온도나 몇 퍼센트 낮게 나오는 습도 같은 경우입니다. 소스 값에 배율을 곱하고 오프셋을 더한 값을 보여줍니다.",
"title": "보정 👻"
}
}
},
"options": {
"step": {
"init": {
"data": {
"entity_id": "소스 엔티티",
"offset": "오프셋",
"factor": "배율"
},
"data_description": {
"offset": "소스 값에 더해집니다. 1.5도 높게 측정하는 센서라면 -1.5를 입력합니다. 단위는 소스가 보고하는 단위입니다.",
"factor": "소스 값에 먼저 이 값을 곱합니다. 오프셋만 더하려면 1로 두세요."
},
"title": "보정 👻"
}
}
},
"title": "보정 👻"
}
@@ -1 +1,37 @@
{} {
"config": {
"step": {
"user": {
"data": {
"entity_id": "Šaltinio subjektas",
"name": "Pavadinimas",
"offset": "Poslinkis",
"factor": "Koeficientas"
},
"data_description": {
"offset": "Pridedamas prie šaltinio reikšmės. Jutikliui, kuris rodo 1,5 laipsnio per daug, nurodykite -1,5. Šaltinio naudojamais vienetais.",
"factor": "Pirmiausia šaltinio reikšmė padauginama iš šio skaičiaus. Palikite 1, jei norite tik pridėti poslinkį."
},
"description": "Šis pagalbininkas pataiso netiksliai rodantį jutiklį: temperatūrą, laipsniu per aukštą, drėgmę, keliais procentais per žemą. Jis rodo šaltinio reikšmę, padaugintą iš koeficiento, plius poslinkį.",
"title": "Kalibravimas 👻"
}
}
},
"options": {
"step": {
"init": {
"data": {
"entity_id": "Šaltinio subjektas",
"offset": "Poslinkis",
"factor": "Koeficientas"
},
"data_description": {
"offset": "Pridedamas prie šaltinio reikšmės. Jutikliui, kuris rodo 1,5 laipsnio per daug, nurodykite -1,5. Šaltinio naudojamais vienetais.",
"factor": "Pirmiausia šaltinio reikšmė padauginama iš šio skaičiaus. Palikite 1, jei norite tik pridėti poslinkį."
},
"title": "Kalibravimas 👻"
}
}
},
"title": "Kalibravimas 👻"
}
@@ -1 +1,37 @@
{} {
"config": {
"step": {
"user": {
"data": {
"entity_id": "Изворен ентитет",
"name": "Име",
"offset": "Поместување",
"factor": "Фактор"
},
"data_description": {
"offset": "Се додава на вредноста на изворот. Сензор што покажува 1,5 степени повеќе добива -1,5. Во единицата во која изворот известува.",
"factor": "Вредноста на изворот прво се множи со ова. Оставете 1 за само да се додаде поместувањето."
},
"description": "Овој помошник исправа сензор што не мери точно: температура за еден степен превисока, влажност неколку проценти прениска. Ја прикажува вредноста на изворот помножена со факторот, плус поместувањето.",
"title": "Калибрација 👻"
}
}
},
"options": {
"step": {
"init": {
"data": {
"entity_id": "Изворен ентитет",
"offset": "Поместување",
"factor": "Фактор"
},
"data_description": {
"offset": "Се додава на вредноста на изворот. Сензор што покажува 1,5 степени повеќе добива -1,5. Во единицата во која изворот известува.",
"factor": "Вредноста на изворот прво се множи со ова. Оставете 1 за само да се додаде поместувањето."
},
"title": "Калибрација 👻"
}
}
},
"title": "Калибрација 👻"
}
@@ -1 +1,37 @@
{} {
"config": {
"step": {
"user": {
"data": {
"entity_id": "Encja źródłowa",
"name": "Nazwa",
"offset": "Przesunięcie",
"factor": "Współczynnik"
},
"data_description": {
"offset": "Dodawane do wartości źródła. Czujnik, który zawyża o 1,5 stopnia, dostaje -1,5. W jednostce, w której raportuje źródło.",
"factor": "Wartość źródła jest najpierw mnożona przez tę liczbę. Zostaw 1, aby tylko dodać przesunięcie."
},
"description": "Ten pomocnik poprawia czujnik, który się myli: temperaturę o stopień za wysoką, wilgotność o kilka procent za niską. Pokazuje wartość źródła razy współczynnik, plus przesunięcie.",
"title": "Kalibracja 👻"
}
}
},
"options": {
"step": {
"init": {
"data": {
"entity_id": "Encja źródłowa",
"offset": "Przesunięcie",
"factor": "Współczynnik"
},
"data_description": {
"offset": "Dodawane do wartości źródła. Czujnik, który zawyża o 1,5 stopnia, dostaje -1,5. W jednostce, w której raportuje źródło.",
"factor": "Wartość źródła jest najpierw mnożona przez tę liczbę. Zostaw 1, aby tylko dodać przesunięcie."
},
"title": "Kalibracja 👻"
}
}
},
"title": "Kalibracja 👻"
}
@@ -1 +1,37 @@
{} {
"config": {
"step": {
"user": {
"data": {
"entity_id": "Entidade de origem",
"name": "Nome",
"offset": "Desvio",
"factor": "Fator"
},
"data_description": {
"offset": "Somado ao valor da origem. Um sensor que lê 1,5 graus a mais recebe -1,5. Na unidade em que a origem reporta.",
"factor": "O valor da origem é primeiro multiplicado por este. Deixa em 1 para apenas somar o desvio."
},
"description": "Este assistente corrige um sensor que lê mal: uma temperatura um grau acima, uma humidade uns pontos percentuais abaixo. Mostra o valor da origem vezes o fator, mais o desvio.",
"title": "Calibração 👻"
}
}
},
"options": {
"step": {
"init": {
"data": {
"entity_id": "Entidade de origem",
"offset": "Desvio",
"factor": "Fator"
},
"data_description": {
"offset": "Somado ao valor da origem. Um sensor que lê 1,5 graus a mais recebe -1,5. Na unidade em que a origem reporta.",
"factor": "O valor da origem é primeiro multiplicado por este. Deixa em 1 para apenas somar o desvio."
},
"title": "Calibração 👻"
}
}
},
"title": "Calibração 👻"
}
@@ -1 +1,37 @@
{} {
"config": {
"step": {
"user": {
"data": {
"entity_id": "Entidade de origem",
"name": "Nome",
"offset": "Deslocamento",
"factor": "Fator"
},
"data_description": {
"offset": "Somado ao valor da origem. Um sensor que marca 1,5 grau a mais recebe -1,5. Na unidade em que a origem informa.",
"factor": "O valor da origem é multiplicado por isto primeiro. Deixe em 1 para apenas somar o deslocamento."
},
"description": "Este auxiliar corrige um sensor que mede errado: uma temperatura um grau acima, uma umidade alguns pontos percentuais abaixo. Mostra o valor da origem vezes o fator, mais o deslocamento.",
"title": "Calibração 👻"
}
}
},
"options": {
"step": {
"init": {
"data": {
"entity_id": "Entidade de origem",
"offset": "Deslocamento",
"factor": "Fator"
},
"data_description": {
"offset": "Somado ao valor da origem. Um sensor que marca 1,5 grau a mais recebe -1,5. Na unidade em que a origem informa.",
"factor": "O valor da origem é multiplicado por isto primeiro. Deixe em 1 para apenas somar o deslocamento."
},
"title": "Calibração 👻"
}
}
},
"title": "Calibração 👻"
}
@@ -1 +1,37 @@
{} {
"config": {
"step": {
"user": {
"data": {
"entity_id": "Исходный объект",
"name": "Имя",
"offset": "Смещение",
"factor": "Коэффициент"
},
"data_description": {
"offset": "Прибавляется к значению источника. Сенсору, который завышает показания на 1,5 градуса, нужно -1,5. В тех единицах, в которых отчитывается источник.",
"factor": "Сначала значение источника умножается на это число. Оставьте 1, чтобы только прибавить смещение."
},
"description": "Этот вспомогательный объект исправляет сенсор, который ошибается: температура на градус выше, влажность на несколько процентов ниже. Он показывает значение источника, умноженное на коэффициент, плюс смещение.",
"title": "Калибровка 👻"
}
}
},
"options": {
"step": {
"init": {
"data": {
"entity_id": "Исходный объект",
"offset": "Смещение",
"factor": "Коэффициент"
},
"data_description": {
"offset": "Прибавляется к значению источника. Сенсору, который завышает показания на 1,5 градуса, нужно -1,5. В тех единицах, в которых отчитывается источник.",
"factor": "Сначала значение источника умножается на это число. Оставьте 1, чтобы только прибавить смещение."
},
"title": "Калибровка 👻"
}
}
},
"title": "Калибровка 👻"
}
@@ -1 +1,37 @@
{} {
"config": {
"step": {
"user": {
"data": {
"entity_id": "Zdrojová entita",
"name": "Názov",
"offset": "Posun",
"factor": "Koeficient"
},
"data_description": {
"offset": "Pripočíta sa k hodnote zdroja. Senzor, ktorý ukazuje o 1,5 stupňa viac, dostane -1,5. V jednotke, v ktorej zdroj hlási.",
"factor": "Hodnota zdroja sa najprv vynásobí týmto číslom. Nechaj 1, ak chceš len pripočítať posun."
},
"description": "Tento pomocník opraví senzor, ktorý meria vedľa: teplotu o stupeň vyššiu, vlhkosť o pár percent nižšiu. Zobrazuje hodnotu zdroja vynásobenú koeficientom, plus posun.",
"title": "Kalibrácia 👻"
}
}
},
"options": {
"step": {
"init": {
"data": {
"entity_id": "Zdrojová entita",
"offset": "Posun",
"factor": "Koeficient"
},
"data_description": {
"offset": "Pripočíta sa k hodnote zdroja. Senzor, ktorý ukazuje o 1,5 stupňa viac, dostane -1,5. V jednotke, v ktorej zdroj hlási.",
"factor": "Hodnota zdroja sa najprv vynásobí týmto číslom. Nechaj 1, ak chceš len pripočítať posun."
},
"title": "Kalibrácia 👻"
}
}
},
"title": "Kalibrácia 👻"
}
@@ -13,7 +13,7 @@
"factor": "Вредност извора се прво множи овим бројем. Оставите 1 ако желите да додате само одступање." "factor": "Вредност извора се прво множи овим бројем. Оставите 1 ако желите да додате само одступање."
}, },
"title": "Калибрација 👻", "title": "Калибрација 👻",
"description": "Овај помоћник исправља сензор који лоше очитава: температуру која је за степен превисока или влажност која је неколико процената прениска. Приказује вредност извора помножену са фактором, плус одступање." "description": "Овај помоћник исправља сензор који очитава нетачне вредности: температуру за степен превисоку или влажност за неколико процената прениску. Приказује вредност извора помножену фактором, плус одступање."
} }
} }
}, },
@@ -1,11 +1,11 @@
{ {
"title": "Kalibracija👻", "title": "Kalibracija 👻",
"options": { "options": {
"step": { "step": {
"init": { "init": {
"title": "Kalibracija👻", "title": "Kalibracija 👻",
"data": { "data": {
"offset": "Одступање", "offset": "Odstupanje",
"factor": "Faktor", "factor": "Faktor",
"entity_id": "Izvorni entitet" "entity_id": "Izvorni entitet"
}, },
@@ -19,7 +19,7 @@
"config": { "config": {
"step": { "step": {
"user": { "user": {
"title": "Kalibracija👻", "title": "Kalibracija 👻",
"data": { "data": {
"offset": "Odstupanje", "offset": "Odstupanje",
"name": "Naziv", "name": "Naziv",
@@ -30,7 +30,7 @@
"offset": "Dodaje se na vrednost izvora. Senzor koji pokazuje 1,5 stepeni više dobija -1,5. Koristi se merna jedinica koju prijavljuje izvor.", "offset": "Dodaje se na vrednost izvora. Senzor koji pokazuje 1,5 stepeni više dobija -1,5. Koristi se merna jedinica koju prijavljuje izvor.",
"factor": "Vrednost izvora se prvo množi ovim brojem. Ostavite 1 ako želite da dodate samo odstupanje." "factor": "Vrednost izvora se prvo množi ovim brojem. Ostavite 1 ako želite da dodate samo odstupanje."
}, },
"description": "Ovaj pomoćnik ispravlja senzor koji loše očitava: temperaturu koja je za stepen previsoka ili vlažnost koja je nekoliko procenata preniska. Prikazuje vrednost izvora pomnoženu sa faktorom, plus odstupanje." "description": "Ovaj pomoćnik ispravlja senzor koji očitava netačne vrednosti: temperaturu za stepen previsoku ili vlažnost za nekoliko procenata prenisku. Prikazuje vrednost izvora pomnoženu faktorom, plus odstupanje."
} }
} }
} }
@@ -1 +1,37 @@
{} {
"config": {
"step": {
"user": {
"data": {
"entity_id": "Källentitet",
"name": "Namn",
"offset": "Förskjutning",
"factor": "Faktor"
},
"data_description": {
"offset": "Läggs till källans värde. En sensor som visar 1,5 grader för mycket får -1,5. I den enhet som källan rapporterar i.",
"factor": "Källans värde multipliceras först med detta. Låt stå på 1 för att bara lägga till förskjutningen."
},
"description": "Denna hjälpare korrigerar en sensor som visar fel: en temperatur en grad för hög, en luftfuktighet några procent för låg. Den visar källans värde gånger faktorn, plus förskjutningen.",
"title": "Kalibrering 👻"
}
}
},
"options": {
"step": {
"init": {
"data": {
"entity_id": "Källentitet",
"offset": "Förskjutning",
"factor": "Faktor"
},
"data_description": {
"offset": "Läggs till källans värde. En sensor som visar 1,5 grader för mycket får -1,5. I den enhet som källan rapporterar i.",
"factor": "Källans värde multipliceras först med detta. Låt stå på 1 för att bara lägga till förskjutningen."
},
"title": "Kalibrering 👻"
}
}
},
"title": "Kalibrering 👻"
}
@@ -1 +1,37 @@
{} {
"config": {
"step": {
"user": {
"data": {
"entity_id": "Kaynak varlık",
"name": "İsim",
"offset": "Telafi",
"factor": "Çarpan"
},
"data_description": {
"offset": "Kaynağın değerine eklenir. 1,5 derece fazla gösteren bir sensöre -1,5 girilir. Kaynağın bildirdiği birim cinsindendir.",
"factor": "Kaynağın değeri önce bununla çarpılır. Yalnızca telafiyi eklemek için 1 olarak bırakın."
},
"description": "Bu yardımcı, yanlış ölçen bir sensörü düzeltir: bir derece fazla gösteren bir sıcaklık, birkaç yüzde eksik gösteren bir nem. Kaynağın değerini çarpanla çarpıp üstüne telafiyi ekleyerek gösterir.",
"title": "Kalibrasyon 👻"
}
}
},
"options": {
"step": {
"init": {
"data": {
"entity_id": "Kaynak varlık",
"offset": "Telafi",
"factor": "Çarpan"
},
"data_description": {
"offset": "Kaynağın değerine eklenir. 1,5 derece fazla gösteren bir sensöre -1,5 girilir. Kaynağın bildirdiği birim cinsindendir.",
"factor": "Kaynağın değeri önce bununla çarpılır. Yalnızca telafiyi eklemek için 1 olarak bırakın."
},
"title": "Kalibrasyon 👻"
}
}
},
"title": "Kalibrasyon 👻"
}
@@ -1 +1,37 @@
{} {
"config": {
"step": {
"user": {
"data": {
"entity_id": "Вихідна сутність",
"name": "Назва",
"offset": "Зміщення",
"factor": "Коефіцієнт"
},
"data_description": {
"offset": "Додається до значення джерела. Датчику, що завищує на 1,5 градуса, потрібно -1,5. В одиницях, у яких звітує джерело.",
"factor": "Спочатку значення джерела множиться на це число. Залиште 1, щоб лише додати зміщення."
},
"description": "Цей помічник виправляє датчик, який показує неточно: температуру на градус вищу, вологість на кілька відсотків нижчу. Він показує значення джерела, помножене на коефіцієнт, плюс зміщення.",
"title": "Калібрування 👻"
}
}
},
"options": {
"step": {
"init": {
"data": {
"entity_id": "Вихідна сутність",
"offset": "Зміщення",
"factor": "Коефіцієнт"
},
"data_description": {
"offset": "Додається до значення джерела. Датчику, що завищує на 1,5 градуса, потрібно -1,5. В одиницях, у яких звітує джерело.",
"factor": "Спочатку значення джерела множиться на це число. Залиште 1, щоб лише додати зміщення."
},
"title": "Калібрування 👻"
}
}
},
"title": "Калібрування 👻"
}
@@ -1 +1,37 @@
{} {
"config": {
"step": {
"user": {
"data": {
"entity_id": "Thực thể nguồn",
"name": "Tên",
"offset": "Độ lệch",
"factor": "Hệ số"
},
"data_description": {
"offset": "Được cộng vào giá trị của nguồn. Cảm biến đọc cao hơn 1,5 độ thì nhập -1,5. Tính theo đơn vị mà nguồn báo cáo.",
"factor": "Giá trị của nguồn được nhân với số này trước. Để 1 nếu chỉ muốn cộng độ lệch."
},
"description": "Biến trợ giúp này hiệu chỉnh một cảm biến đọc sai: nhiệt độ cao hơn một độ, độ ẩm thấp hơn vài phần trăm. Nó hiển thị giá trị của nguồn nhân với hệ số, cộng với độ lệch.",
"title": "Hiệu chỉnh 👻"
}
}
},
"options": {
"step": {
"init": {
"data": {
"entity_id": "Thực thể nguồn",
"offset": "Độ lệch",
"factor": "Hệ số"
},
"data_description": {
"offset": "Được cộng vào giá trị của nguồn. Cảm biến đọc cao hơn 1,5 độ thì nhập -1,5. Tính theo đơn vị mà nguồn báo cáo.",
"factor": "Giá trị của nguồn được nhân với số này trước. Để 1 nếu chỉ muốn cộng độ lệch."
},
"title": "Hiệu chỉnh 👻"
}
}
},
"title": "Hiệu chỉnh 👻"
}
@@ -1 +1,37 @@
{} {
"config": {
"step": {
"user": {
"data": {
"entity_id": "源实体",
"name": "名称",
"offset": "偏移",
"factor": "系数"
},
"data_description": {
"offset": "加到源的数值上。读数偏高 1.5 度的传感器就填 -1.5。单位与源上报的单位相同。",
"factor": "源的数值会先乘以这个数。只想加偏移的话,保持为 1 即可。"
},
"description": "此辅助程序用于校正读数不准的传感器:温度高了一度,湿度低了几个百分点。它显示的是源的数值乘以系数,再加上偏移。",
"title": "校准 👻"
}
}
},
"options": {
"step": {
"init": {
"data": {
"entity_id": "源实体",
"offset": "偏移",
"factor": "系数"
},
"data_description": {
"offset": "加到源的数值上。读数偏高 1.5 度的传感器就填 -1.5。单位与源上报的单位相同。",
"factor": "源的数值会先乘以这个数。只想加偏移的话,保持为 1 即可。"
},
"title": "校准 👻"
}
}
},
"title": "校准 👻"
}
@@ -1 +1,37 @@
{} {
"config": {
"step": {
"user": {
"data": {
"entity_id": "源實體",
"name": "名稱",
"offset": "偏移",
"factor": "係數"
},
"data_description": {
"offset": "加到源的數值上。讀數偏高 1.5 度的感測器就填 -1.5。單位與源回報的單位相同。",
"factor": "源的數值會先乘以此數。若只想加上偏移,保持為 1 即可。"
},
"description": "這項輔助項目用於校正讀數不準的感測器:溫度高了一度、濕度低了幾個百分點。它顯示的是源的數值乘以係數,再加上偏移。",
"title": "校準 👻"
}
}
},
"options": {
"step": {
"init": {
"data": {
"entity_id": "源實體",
"offset": "偏移",
"factor": "係數"
},
"data_description": {
"offset": "加到源的數值上。讀數偏高 1.5 度的感測器就填 -1.5。單位與源回報的單位相同。",
"factor": "源的數值會先乘以此數。若只想加上偏移,保持為 1 即可。"
},
"title": "校準 👻"
}
}
},
"title": "校準 👻"
}
@@ -10,5 +10,5 @@
"iot_class": "calculated", "iot_class": "calculated",
"issue_tracker": "https://github.com/frenck/spook/issues", "issue_tracker": "https://github.com/frenck/spook/issues",
"requirements": [], "requirements": [],
"version": "5.9.0" "version": "5.10.0"
} }
@@ -3,13 +3,47 @@
"step": { "step": {
"binary_sensor": { "binary_sensor": {
"data": { "data": {
"entity_id": "Entitat d'origen",
"hide_source": "Amaga l'entitat d'origen",
"name": "Nom" "name": "Nom"
} },
"title": "Inversió 👻"
},
"cover": {
"data": {
"entity_id": "Entitat d'origen",
"hide_source": "Amaga l'entitat d'origen",
"inverse_position": "Inverteix l'obertura, el tancament i la posició",
"inverse_tilt": "Inverteix la inclinació",
"name": "Nom"
},
"title": "Inversió 👻"
}, },
"switch": { "switch": {
"data": { "data": {
"entity_id": "Entitat d'origen",
"hide_source": "Amaga l'entitat d'origen",
"name": "Nom" "name": "Nom"
} },
"title": "Inversió 👻"
},
"valve": {
"data": {
"entity_id": "Entitat d'origen",
"hide_source": "Amaga l'entitat d'origen",
"name": "Nom"
},
"title": "Inversió 👻"
},
"user": {
"description": "Aquest ajudant et permet invertir el comportament d'una entitat. Per exemple, intercanviar obert/tancat o encès/apagat de sensors binaris, cobertes, interruptors i vàlvules.",
"menu_options": {
"binary_sensor": "Inverteix un sensor binari",
"cover": "Inverteix una coberta",
"switch": "Inverteix un interruptor",
"valve": "Inverteix una vàlvula"
},
"title": "Inversió 👻"
} }
} }
}, },
@@ -17,14 +51,39 @@
"step": { "step": {
"binary_sensor": { "binary_sensor": {
"data": { "data": {
"entity_id": "Entitat d'origen",
"hide_source": "Amaga l'entitat d'origen",
"name": "Nom" "name": "Nom"
} },
"title": "Inversió 👻"
},
"cover": {
"data": {
"entity_id": "Entitat d'origen",
"hide_source": "Amaga l'entitat d'origen",
"inverse_position": "Inverteix l'obertura, el tancament i la posició",
"inverse_tilt": "Inverteix la inclinació",
"name": "Nom"
},
"title": "Inversió 👻"
}, },
"switch": { "switch": {
"data": { "data": {
"entity_id": "Entitat d'origen",
"hide_source": "Amaga l'entitat d'origen",
"name": "Nom" "name": "Nom"
} },
"title": "Inversió 👻"
},
"valve": {
"data": {
"entity_id": "Entitat d'origen",
"hide_source": "Amaga l'entitat d'origen",
"name": "Nom"
},
"title": "Inversió 👻"
} }
} }
} },
"title": "Inversió 👻"
} }
@@ -9,6 +9,16 @@
}, },
"title": "Invertovat 👻" "title": "Invertovat 👻"
}, },
"cover": {
"data": {
"entity_id": "Zdrojová entita",
"hide_source": "Skrýt zdrojovou entitu",
"inverse_position": "Invertovat otevírání, zavírání a polohu",
"inverse_tilt": "Invertovat náklon",
"name": "Název"
},
"title": "Invertovat 👻"
},
"switch": { "switch": {
"data": { "data": {
"entity_id": "Zdrojová entita", "entity_id": "Zdrojová entita",
@@ -17,13 +27,23 @@
}, },
"title": "Invertovat 👻" "title": "Invertovat 👻"
}, },
"valve": {
"data": {
"entity_id": "Zdrojová entita",
"hide_source": "Skrýt zdrojovou entitu",
"name": "Název"
},
"title": "Invertovat 👻"
},
"user": { "user": {
"title": "Invertovat 👻", "title": "Invertovat 👻",
"menu_options": { "menu_options": {
"binary_sensor": "Invertovat binární senzor", "binary_sensor": "Invertovat binární senzor",
"switch": "Invertovat přepínač" "cover": "Invertovat kryt",
"switch": "Invertovat přepínač",
"valve": "Invertovat ventil"
}, },
"description": "Tento pomocník umožňuje invertovat chování entity. Například otočení otevřeno/zavřeno nebo zapnuto/vypnuto binárního senzoru či přepínače." "description": "Tento pomocník umožňuje invertovat chování entity. Například prohodit otevřeno/zavřeno nebo zapnuto/vypnuto u binárních senzorů, krytů, přepínačů a ventilů."
} }
} }
}, },
@@ -37,6 +57,16 @@
}, },
"title": "Invertovat 👻" "title": "Invertovat 👻"
}, },
"cover": {
"data": {
"entity_id": "Zdrojová entita",
"hide_source": "Skrýt zdrojovou entitu",
"inverse_position": "Invertovat otevírání, zavírání a polohu",
"inverse_tilt": "Invertovat náklon",
"name": "Název"
},
"title": "Invertovat 👻"
},
"switch": { "switch": {
"data": { "data": {
"entity_id": "Zdrojová entita", "entity_id": "Zdrojová entita",
@@ -44,6 +74,14 @@
"name": "Název" "name": "Název"
}, },
"title": "Invertovat 👻" "title": "Invertovat 👻"
},
"valve": {
"data": {
"entity_id": "Zdrojová entita",
"hide_source": "Skrýt zdrojovou entitu",
"name": "Název"
},
"title": "Invertovat 👻"
} }
} }
}, },
@@ -4,24 +4,44 @@
"switch": { "switch": {
"data": { "data": {
"name": "Navn", "name": "Navn",
"hide_source": "Skjul kildeenhed", "hide_source": "Skjul kildeentitet",
"entity_id": "Kildeenhed" "entity_id": "Kildeentitet"
},
"title": "Invertér 👻"
},
"valve": {
"data": {
"entity_id": "Kildeentitet",
"hide_source": "Skjul kildeentitet",
"name": "Navn"
}, },
"title": "Invertér 👻" "title": "Invertér 👻"
}, },
"binary_sensor": { "binary_sensor": {
"data": { "data": {
"hide_source": "Skjul kildeenhed", "hide_source": "Skjul kildeentitet",
"name": "Navn", "name": "Navn",
"entity_id": "Kildeenhed" "entity_id": "Kildeentitet"
},
"title": "Invertér 👻"
},
"cover": {
"data": {
"entity_id": "Kildeentitet",
"hide_source": "Skjul kildeentitet",
"inverse_position": "Invertér åbning, lukning og position",
"inverse_tilt": "Invertér vippeposition",
"name": "Navn"
}, },
"title": "Invertér 👻" "title": "Invertér 👻"
}, },
"user": { "user": {
"description": "Denne hjælper tillader dig at invertere logikken for en enhed. Fx. fra åben til lukket eller fra tændt til slukket på binære sensorer og afbrydere.", "description": "Denne hjælper lader dig invertere en entitets adfærd. For eksempel vende åben/lukket eller tændt/slukket om for binære sensorer, gardiner/porte, kontakter og ventiler.",
"menu_options": { "menu_options": {
"binary_sensor": "Invertér en binær sensor", "binary_sensor": "Invertér en binær sensor",
"switch": "Invertér en afbryder" "cover": "Invertér et gardin/port",
"switch": "Invertér en kontakt",
"valve": "Invertér en ventil"
}, },
"title": "Invertér 👻" "title": "Invertér 👻"
} }
@@ -31,17 +51,35 @@
"step": { "step": {
"binary_sensor": { "binary_sensor": {
"data": { "data": {
"entity_id": "Kildeenhed", "entity_id": "Kildeentitet",
"name": "Navn", "name": "Navn",
"hide_source": "Skjul kildeenhed" "hide_source": "Skjul kildeentitet"
},
"title": "Invertér 👻"
},
"cover": {
"data": {
"entity_id": "Kildeentitet",
"hide_source": "Skjul kildeentitet",
"inverse_position": "Invertér åbning, lukning og position",
"inverse_tilt": "Invertér vippeposition",
"name": "Navn"
}, },
"title": "Invertér 👻" "title": "Invertér 👻"
}, },
"switch": { "switch": {
"data": { "data": {
"entity_id": "Kildeenhed", "entity_id": "Kildeentitet",
"name": "Navn", "name": "Navn",
"hide_source": "Skjul kildeenhed" "hide_source": "Skjul kildeentitet"
},
"title": "Invertér 👻"
},
"valve": {
"data": {
"entity_id": "Kildeentitet",
"hide_source": "Skjul kildeentitet",
"name": "Navn"
}, },
"title": "Invertér 👻" "title": "Invertér 👻"
} }
@@ -15,8 +15,8 @@
"menu_options": { "menu_options": {
"switch": "Einen Schalter umkehren", "switch": "Einen Schalter umkehren",
"binary_sensor": "Einen binären Sensor umkehren", "binary_sensor": "Einen binären Sensor umkehren",
"cover": "Abdeckung invertieren", "cover": "Eine Abdeckung umkehren",
"valve": "Ein Ventil invertieren" "valve": "Ein Ventil umkehren"
}, },
"title": "Umkehren 👻" "title": "Umkehren 👻"
}, },
@@ -32,11 +32,11 @@
"data": { "data": {
"entity_id": "Quell-Entität", "entity_id": "Quell-Entität",
"hide_source": "Quell-Entität verbergen", "hide_source": "Quell-Entität verbergen",
"inverse_tilt": "Neigung invertieren", "inverse_tilt": "Kippstellung umkehren",
"name": "Name", "name": "Name",
"inverse_position": "Invertiert offen, geschlossen und Position" "inverse_position": "Öffnen, Schließen und Position umkehren"
}, },
"title": "Invertieren 👻" "title": "Umkehren 👻"
}, },
"valve": { "valve": {
"data": { "data": {
@@ -44,7 +44,7 @@
"hide_source": "Quell-Entität verbergen", "hide_source": "Quell-Entität verbergen",
"name": "Name" "name": "Name"
}, },
"title": "Invertieren 👻" "title": "Umkehren 👻"
} }
} }
}, },
@@ -71,10 +71,10 @@
"entity_id": "Quell-Entität", "entity_id": "Quell-Entität",
"hide_source": "Quell-Entität verbergen", "hide_source": "Quell-Entität verbergen",
"name": "Name", "name": "Name",
"inverse_tilt": "Neigung invertieren", "inverse_tilt": "Kippstellung umkehren",
"inverse_position": "Invertiert öffnen, schliessen und Position" "inverse_position": "Öffnen, Schließen und Position umkehren"
}, },
"title": "Invertieren 👻" "title": "Umkehren 👻"
}, },
"valve": { "valve": {
"data": { "data": {
@@ -82,7 +82,7 @@
"name": "Name", "name": "Name",
"entity_id": "Quell-Entität" "entity_id": "Quell-Entität"
}, },
"title": "Invertieren 👻" "title": "Umkehren 👻"
} }
} }
} }
@@ -4,27 +4,47 @@
"step": { "step": {
"switch": { "switch": {
"data": { "data": {
"name": "Ονομα", "name": "Όνομα",
"hide_source": "Απόκρυψη οντότητας πηγής", "hide_source": "Απόκρυψη οντότητας πηγής",
"entity_id": "Οντότητα πηγής" "entity_id": "Οντότητα πηγής"
}, },
"title": "Αντιστροφή 👻" "title": "Αντιστροφή 👻"
}, },
"valve": {
"data": {
"entity_id": "Οντότητα πηγής",
"hide_source": "Απόκρυψη οντότητας πηγής",
"name": "Όνομα"
},
"title": "Αντιστροφή 👻"
},
"user": { "user": {
"description": "Αυτός ο βοηθός σάς επιτρέπει να αντιστρέψετε τη συμπεριφορά μιας οντότητας. Για παράδειγμα, αντιστρέψτε το άνοιγμα/κλείσιμο ή την ενεργοποίηση/απενεργοποίηση δυαδικών αισθητήρων και διακοπτών.", "description": "Αυτός ο βοηθός σάς επιτρέπει να αντιστρέψετε τη συμπεριφορά μιας οντότητας. Για παράδειγμα, αντιστρέψτε το άνοιγμα/κλείσιμο ή την ενεργοποίηση/απενεργοποίηση δυαδικών αισθητήρων, ρολών, διακοπτών και βαλβίδων.",
"menu_options": { "menu_options": {
"switch": "Αντιστροφή ενός διακόπτη", "switch": "Αντιστροφή ενός διακόπτη",
"binary_sensor": "Αντιστροφή ενός δυαδικού αισθητήρα" "valve": "Αντιστροφή μιας βαλβίδας",
"binary_sensor": "Αντιστροφή ενός δυαδικού αισθητήρα",
"cover": "Αντιστροφή ενός ρολού"
}, },
"title": "Αντιστροφή 👻" "title": "Αντιστροφή 👻"
}, },
"binary_sensor": { "binary_sensor": {
"data": { "data": {
"hide_source": "Απόκρυψη οντότητας πηγής", "hide_source": "Απόκρυψη οντότητας πηγής",
"name": "Ονομα", "name": "Όνομα",
"entity_id": "Οντότητα πηγής" "entity_id": "Οντότητα πηγής"
}, },
"title": "Αντιστροφή 👻" "title": "Αντιστροφή 👻"
},
"cover": {
"data": {
"entity_id": "Οντότητα πηγής",
"hide_source": "Απόκρυψη οντότητας πηγής",
"inverse_position": "Αντιστροφή ανοίγματος, κλεισίματος και θέσης",
"inverse_tilt": "Αντιστροφή κλίσης",
"name": "Όνομα"
},
"title": "Αντιστροφή 👻"
} }
} }
}, },
@@ -34,17 +54,35 @@
"data": { "data": {
"hide_source": "Απόκρυψη οντότητας πηγής", "hide_source": "Απόκρυψη οντότητας πηγής",
"entity_id": "Οντότητα πηγής", "entity_id": "Οντότητα πηγής",
"name": "Ονομα" "name": "Όνομα"
},
"title": "Αντιστροφή 👻"
},
"valve": {
"data": {
"entity_id": "Οντότητα πηγής",
"hide_source": "Απόκρυψη οντότητας πηγής",
"name": "Όνομα"
}, },
"title": "Αντιστροφή 👻" "title": "Αντιστροφή 👻"
}, },
"binary_sensor": { "binary_sensor": {
"title": "Αντιστροφή 👻", "title": "Αντιστροφή 👻",
"data": { "data": {
"name": "Ονομα", "name": "Όνομα",
"hide_source": "Απόκρυψη οντότητας πηγής", "hide_source": "Απόκρυψη οντότητας πηγής",
"entity_id": "Οντότητα πηγής" "entity_id": "Οντότητα πηγής"
} }
},
"cover": {
"data": {
"entity_id": "Οντότητα πηγής",
"hide_source": "Απόκρυψη οντότητας πηγής",
"inverse_position": "Αντιστροφή ανοίγματος, κλεισίματος και θέσης",
"inverse_tilt": "Αντιστροφή κλίσης",
"name": "Όνομα"
},
"title": "Αντιστροφή 👻"
} }
} }
} }
@@ -13,8 +13,8 @@
"data": { "data": {
"entity_id": "Source entity", "entity_id": "Source entity",
"hide_source": "Hide source entity", "hide_source": "Hide source entity",
"inverse_position": "Inverse opening, closing and position", "inverse_position": "Invert opening, closing and position",
"inverse_tilt": "Inverse tilt", "inverse_tilt": "Invert tilt",
"name": "Name" "name": "Name"
}, },
"title": "Inverse 👻" "title": "Inverse 👻"
@@ -38,10 +38,10 @@
"user": { "user": {
"description": "This helper allows you to invert the behavior of an entity. For example, reverse the open/close or on/off of binary sensors, covers, switches, and valves.", "description": "This helper allows you to invert the behavior of an entity. For example, reverse the open/close or on/off of binary sensors, covers, switches, and valves.",
"menu_options": { "menu_options": {
"binary_sensor": "Inverse a binary sensor", "binary_sensor": "Invert a binary sensor",
"cover": "Inverse a cover", "cover": "Invert a cover",
"switch": "Inverse a switch", "switch": "Invert a switch",
"valve": "Inverse a valve" "valve": "Invert a valve"
}, },
"title": "Inverse 👻" "title": "Inverse 👻"
} }
@@ -61,8 +61,8 @@
"data": { "data": {
"entity_id": "Source entity", "entity_id": "Source entity",
"hide_source": "Hide source entity", "hide_source": "Hide source entity",
"inverse_position": "Inverse opening, closing and position", "inverse_position": "Invert opening, closing and position",
"inverse_tilt": "Inverse tilt", "inverse_tilt": "Invert tilt",
"name": "Name" "name": "Name"
}, },
"title": "Inverse 👻" "title": "Inverse 👻"
@@ -2,10 +2,12 @@
"config": { "config": {
"step": { "step": {
"user": { "user": {
"description": "This helper allow you to invert the behaviour of an entity. For example, reverse the open/close or on/off of binary sensors, and switches.", "description": "This helper allows you to invert the behaviour of an entity. For example, reverse the open/close or on/off of binary sensors, covers, switches, and valves.",
"menu_options": { "menu_options": {
"binary_sensor": "Invert a binary sensor", "binary_sensor": "Invert a binary sensor",
"switch": "Invert a switch" "cover": "Invert a cover",
"switch": "Invert a switch",
"valve": "Invert a valve"
}, },
"title": "Inverse 👻" "title": "Inverse 👻"
}, },
@@ -17,6 +19,16 @@
}, },
"title": "Inverse 👻" "title": "Inverse 👻"
}, },
"cover": {
"data": {
"entity_id": "Source entity",
"hide_source": "Hide source entity",
"inverse_position": "Invert opening, closing and position",
"inverse_tilt": "Invert tilt",
"name": "Name"
},
"title": "Inverse 👻"
},
"switch": { "switch": {
"data": { "data": {
"entity_id": "Source entity", "entity_id": "Source entity",
@@ -24,6 +36,14 @@
"name": "Name" "name": "Name"
}, },
"title": "Inverse 👻" "title": "Inverse 👻"
},
"valve": {
"data": {
"entity_id": "Source entity",
"hide_source": "Hide source entity",
"name": "Name"
},
"title": "Inverse 👻"
} }
} }
}, },
@@ -37,6 +57,16 @@
}, },
"title": "Inverse 👻" "title": "Inverse 👻"
}, },
"cover": {
"data": {
"entity_id": "Source entity",
"hide_source": "Hide source entity",
"inverse_position": "Invert opening, closing and position",
"inverse_tilt": "Invert tilt",
"name": "Name"
},
"title": "Inverse 👻"
},
"switch": { "switch": {
"data": { "data": {
"entity_id": "Source entity", "entity_id": "Source entity",
@@ -44,6 +74,14 @@
"name": "Name" "name": "Name"
}, },
"title": "Inverse 👻" "title": "Inverse 👻"
},
"valve": {
"data": {
"entity_id": "Source entity",
"hide_source": "Hide source entity",
"name": "Name"
},
"title": "Inverse 👻"
} }
} }
}, },
@@ -5,13 +5,13 @@
"switch": { "switch": {
"data": { "data": {
"name": "Nombre", "name": "Nombre",
"hide_source": "Ocultar entidad origen", "hide_source": "Ocultar entidad de origen",
"entity_id": "Entidad origen" "entity_id": "Entidad de origen"
}, },
"title": "Invertir 👻" "title": "Invertir 👻"
}, },
"user": { "user": {
"description": "Este ayudante te permite invertir el comportamiento de una entidad. Por ejemplo, invertir abrir/cerrar o encender/apagar de sensores binarios, e interruptores.", "description": "Este ayudante te permite invertir el comportamiento de una entidad. Por ejemplo, invertir abrir/cerrar o encender/apagar de sensores binarios, persianas, interruptores y válvulas.",
"menu_options": { "menu_options": {
"switch": "Invertir un interruptor", "switch": "Invertir un interruptor",
"binary_sensor": "Invertir un sensor binario", "binary_sensor": "Invertir un sensor binario",
@@ -22,16 +22,17 @@
}, },
"binary_sensor": { "binary_sensor": {
"data": { "data": {
"hide_source": "Ocultar entidad origen", "hide_source": "Ocultar entidad de origen",
"name": "Nombre", "name": "Nombre",
"entity_id": "Entidad origen" "entity_id": "Entidad de origen"
}, },
"title": "Invertir 👻" "title": "Invertir 👻"
}, },
"cover": { "cover": {
"data": { "data": {
"entity_id": "Entidad origen", "entity_id": "Entidad de origen",
"inverse_position": "Invertir apertura, cierre y poisición", "hide_source": "Ocultar entidad de origen",
"inverse_position": "Invertir apertura, cierre y posición",
"inverse_tilt": "Invertir inclinación", "inverse_tilt": "Invertir inclinación",
"name": "Nombre" "name": "Nombre"
}, },
@@ -39,8 +40,8 @@
}, },
"valve": { "valve": {
"data": { "data": {
"entity_id": "Entidad origen", "entity_id": "Entidad de origen",
"hide_source": "Ocultar entidad origen", "hide_source": "Ocultar entidad de origen",
"name": "Nombre" "name": "Nombre"
}, },
"title": "Invertir 👻" "title": "Invertir 👻"
@@ -51,8 +52,8 @@
"step": { "step": {
"switch": { "switch": {
"data": { "data": {
"hide_source": "Ocultar entidad origen", "hide_source": "Ocultar entidad de origen",
"entity_id": "Entidad origen", "entity_id": "Entidad de origen",
"name": "Nombre" "name": "Nombre"
}, },
"title": "Invertir 👻" "title": "Invertir 👻"
@@ -61,14 +62,14 @@
"title": "Invertir 👻", "title": "Invertir 👻",
"data": { "data": {
"name": "Nombre", "name": "Nombre",
"hide_source": "Ocultar entidad origen", "hide_source": "Ocultar entidad de origen",
"entity_id": "Entidad origen" "entity_id": "Entidad de origen"
} }
}, },
"cover": { "cover": {
"data": { "data": {
"entity_id": "Entidad origen", "entity_id": "Entidad de origen",
"hide_source": "Ocultar entidad origen", "hide_source": "Ocultar entidad de origen",
"inverse_position": "Invertir apertura, cierre y posición", "inverse_position": "Invertir apertura, cierre y posición",
"inverse_tilt": "Invertir inclinación", "inverse_tilt": "Invertir inclinación",
"name": "Nombre" "name": "Nombre"
@@ -77,8 +78,8 @@
}, },
"valve": { "valve": {
"data": { "data": {
"entity_id": "Entidad origen", "entity_id": "Entidad de origen",
"hide_source": "Ocultar entidad origen", "hide_source": "Ocultar entidad de origen",
"name": "Nombre" "name": "Nombre"
}, },
"title": "Invertir 👻" "title": "Invertir 👻"
@@ -1 +1,89 @@
{} {
"config": {
"step": {
"binary_sensor": {
"data": {
"entity_id": "Entidad de origen",
"hide_source": "Ocultar entidad de origen",
"name": "Nombre"
},
"title": "Invertir 👻"
},
"cover": {
"data": {
"entity_id": "Entidad de origen",
"hide_source": "Ocultar entidad de origen",
"inverse_position": "Invertir apertura, cierre y posición",
"inverse_tilt": "Invertir inclinación",
"name": "Nombre"
},
"title": "Invertir 👻"
},
"switch": {
"data": {
"entity_id": "Entidad de origen",
"hide_source": "Ocultar entidad de origen",
"name": "Nombre"
},
"title": "Invertir 👻"
},
"valve": {
"data": {
"entity_id": "Entidad de origen",
"hide_source": "Ocultar entidad de origen",
"name": "Nombre"
},
"title": "Invertir 👻"
},
"user": {
"description": "Este ayudante te permite invertir el comportamiento de una entidad. Por ejemplo, invertir abrir/cerrar o encender/apagar de sensores binarios, persianas, interruptores y válvulas.",
"menu_options": {
"binary_sensor": "Invertir un sensor binario",
"cover": "Invertir una persiana",
"switch": "Invertir un interruptor",
"valve": "Invertir una válvula"
},
"title": "Invertir 👻"
}
}
},
"options": {
"step": {
"binary_sensor": {
"data": {
"entity_id": "Entidad de origen",
"hide_source": "Ocultar entidad de origen",
"name": "Nombre"
},
"title": "Invertir 👻"
},
"cover": {
"data": {
"entity_id": "Entidad de origen",
"hide_source": "Ocultar entidad de origen",
"inverse_position": "Invertir apertura, cierre y posición",
"inverse_tilt": "Invertir inclinación",
"name": "Nombre"
},
"title": "Invertir 👻"
},
"switch": {
"data": {
"entity_id": "Entidad de origen",
"hide_source": "Ocultar entidad de origen",
"name": "Nombre"
},
"title": "Invertir 👻"
},
"valve": {
"data": {
"entity_id": "Entidad de origen",
"hide_source": "Ocultar entidad de origen",
"name": "Nombre"
},
"title": "Invertir 👻"
}
}
},
"title": "Invertir 👻"
}
@@ -7,7 +7,17 @@
"hide_source": "Peida lähteolem", "hide_source": "Peida lähteolem",
"name": "Nimi" "name": "Nimi"
}, },
"title": "Pööra ümber" "title": "Pööra ümber 👻"
},
"cover": {
"data": {
"entity_id": "Lähteolem",
"hide_source": "Peida lähteolem",
"inverse_position": "Pööra ümber avamine, sulgemine ja asend",
"inverse_tilt": "Pööra ümber kalle",
"name": "Nimi"
},
"title": "Pööra ümber 👻"
}, },
"switch": { "switch": {
"data": { "data": {
@@ -15,14 +25,24 @@
"name": "Nimi", "name": "Nimi",
"entity_id": "Lähteolem" "entity_id": "Lähteolem"
}, },
"title": "Pööra ümber" "title": "Pööra ümber 👻"
},
"valve": {
"data": {
"entity_id": "Lähteolem",
"hide_source": "Peida lähteolem",
"name": "Nimi"
},
"title": "Pööra ümber 👻"
}, },
"user": { "user": {
"description": "See abimees võimaldab olemi käitumist ümber pöörata. Näiteks pöörake binaarandurite ja lülitite avatud/suletud või sisse/välja.", "description": "See abiline võimaldab olemi käitumist ümber pöörata. Näiteks pööra binaarandurite, kardinate, lülitite ja ventiilide avatud/suletud või sees/väljas ümber.",
"title": "Pööra ümber", "title": "Pööra ümber 👻",
"menu_options": { "menu_options": {
"binary_sensor": "Binaaranduri ümberpööramine", "binary_sensor": "Binaaranduri ümberpööramine",
"switch": "Lüliti ümberpööramine" "cover": "Kardina ümberpööramine",
"switch": "Lüliti ümberpööramine",
"valve": "Ventiili ümberpööramine"
} }
} }
} }
@@ -32,9 +52,38 @@
"binary_sensor": { "binary_sensor": {
"data": { "data": {
"entity_id": "Lähteolem", "entity_id": "Lähteolem",
"hide_source": "Peida lähteolem" "hide_source": "Peida lähteolem",
} "name": "Nimi"
},
"title": "Pööra ümber 👻"
},
"cover": {
"data": {
"entity_id": "Lähteolem",
"hide_source": "Peida lähteolem",
"inverse_position": "Pööra ümber avamine, sulgemine ja asend",
"inverse_tilt": "Pööra ümber kalle",
"name": "Nimi"
},
"title": "Pööra ümber 👻"
},
"switch": {
"data": {
"entity_id": "Lähteolem",
"hide_source": "Peida lähteolem",
"name": "Nimi"
},
"title": "Pööra ümber 👻"
},
"valve": {
"data": {
"entity_id": "Lähteolem",
"hide_source": "Peida lähteolem",
"name": "Nimi"
},
"title": "Pööra ümber 👻"
} }
} }
} },
"title": "Pööra ümber 👻"
} }
@@ -1 +1,89 @@
{} {
"config": {
"step": {
"binary_sensor": {
"data": {
"entity_id": "Iturburu-entitatea",
"hide_source": "Ezkutatu iturburu-entitatea",
"name": "Izena"
},
"title": "Alderantzikatzea 👻"
},
"cover": {
"data": {
"entity_id": "Iturburu-entitatea",
"hide_source": "Ezkutatu iturburu-entitatea",
"inverse_position": "Alderantzikatu irekitzea, ixtea eta posizioa",
"inverse_tilt": "Alderantzikatu inklinazioa",
"name": "Izena"
},
"title": "Alderantzikatzea 👻"
},
"switch": {
"data": {
"entity_id": "Iturburu-entitatea",
"hide_source": "Ezkutatu iturburu-entitatea",
"name": "Izena"
},
"title": "Alderantzikatzea 👻"
},
"valve": {
"data": {
"entity_id": "Iturburu-entitatea",
"hide_source": "Ezkutatu iturburu-entitatea",
"name": "Izena"
},
"title": "Alderantzikatzea 👻"
},
"user": {
"description": "Laguntzaile honek entitate baten portaera alderantzikatzeko aukera ematen dizu. Adibidez, sentsore bitar, estalki, etengailu eta balbulen irekita/itxita edo piztuta/itzalita trukatzeko.",
"menu_options": {
"binary_sensor": "Alderantzikatu sentsore bitar bat",
"cover": "Alderantzikatu estalki bat",
"switch": "Alderantzikatu etengailu bat",
"valve": "Alderantzikatu balbula bat"
},
"title": "Alderantzikatzea 👻"
}
}
},
"options": {
"step": {
"binary_sensor": {
"data": {
"entity_id": "Iturburu-entitatea",
"hide_source": "Ezkutatu iturburu-entitatea",
"name": "Izena"
},
"title": "Alderantzikatzea 👻"
},
"cover": {
"data": {
"entity_id": "Iturburu-entitatea",
"hide_source": "Ezkutatu iturburu-entitatea",
"inverse_position": "Alderantzikatu irekitzea, ixtea eta posizioa",
"inverse_tilt": "Alderantzikatu inklinazioa",
"name": "Izena"
},
"title": "Alderantzikatzea 👻"
},
"switch": {
"data": {
"entity_id": "Iturburu-entitatea",
"hide_source": "Ezkutatu iturburu-entitatea",
"name": "Izena"
},
"title": "Alderantzikatzea 👻"
},
"valve": {
"data": {
"entity_id": "Iturburu-entitatea",
"hide_source": "Ezkutatu iturburu-entitatea",
"name": "Izena"
},
"title": "Alderantzikatzea 👻"
}
}
},
"title": "Alderantzikatzea 👻"
}
@@ -9,11 +9,23 @@
}, },
"title": "Käännä 👻" "title": "Käännä 👻"
}, },
"cover": {
"data": {
"entity_id": "Lähde-entiteetti",
"hide_source": "Piilota lähde-entiteetti",
"inverse_position": "Käännä avaaminen, sulkeminen ja asento",
"inverse_tilt": "Käännä kallistus",
"name": "Nimi"
},
"title": "Käännä 👻"
},
"user": { "user": {
"description": "Tämän apurin avulla voit vaihtaa entiteetin toiminnan päinvastaiseksi. Voit esimerkiksi vaihtaa binäärisensoreiden ja kytkimien päällä/pois tai auki/kiinni arvot käänteisiksi.", "description": "Tämän apurin avulla voit vaihtaa entiteetin toiminnan päinvastaiseksi. Voit esimerkiksi vaihtaa binäärisensoreiden, kaihtimien, kytkimien ja venttiilien auki/kiinni- tai päällä/pois-tilan käänteiseksi.",
"menu_options": { "menu_options": {
"binary_sensor": "Käännä binäärisensori", "binary_sensor": "Käännä binäärisensori",
"switch": "Käännä kytkin" "cover": "Käännä kaihdin",
"switch": "Käännä kytkin",
"valve": "Käännä venttiili"
}, },
"title": "Käännä 👻" "title": "Käännä 👻"
}, },
@@ -24,6 +36,14 @@
"name": "Nimi" "name": "Nimi"
}, },
"title": "Käännä 👻" "title": "Käännä 👻"
},
"valve": {
"data": {
"entity_id": "Lähde-entiteetti",
"hide_source": "Piilota lähde-entiteetti",
"name": "Nimi"
},
"title": "Käännä 👻"
} }
} }
}, },
@@ -37,6 +57,14 @@
}, },
"title": "Käännä 👻" "title": "Käännä 👻"
}, },
"valve": {
"data": {
"entity_id": "Lähde-entiteetti",
"hide_source": "Piilota lähde-entiteetti",
"name": "Nimi"
},
"title": "Käännä 👻"
},
"binary_sensor": { "binary_sensor": {
"data": { "data": {
"entity_id": "Lähde-entiteetti", "entity_id": "Lähde-entiteetti",
@@ -44,6 +72,16 @@
"name": "Nimi" "name": "Nimi"
}, },
"title": "Käännä 👻" "title": "Käännä 👻"
},
"cover": {
"data": {
"entity_id": "Lähde-entiteetti",
"hide_source": "Piilota lähde-entiteetti",
"inverse_position": "Käännä avaaminen, sulkeminen ja asento",
"inverse_tilt": "Käännä kallistus",
"name": "Nimi"
},
"title": "Käännä 👻"
} }
} }
}, },
@@ -4,26 +4,46 @@
"binary_sensor": { "binary_sensor": {
"data": { "data": {
"name": "Nom", "name": "Nom",
"hide_source": "Cacher l'entité d'origine", "hide_source": "Masquer l'entité source",
"entity_id": "Entité d'origine" "entity_id": "Entité source"
}, },
"title": "Inverser 👻" "title": "Inverser 👻"
}, },
"switch": { "switch": {
"data": { "data": {
"entity_id": "Entité d'origine", "entity_id": "Entité source",
"name": "Nom", "name": "Nom",
"hide_source": "Cacher l'entité d'origine" "hide_source": "Masquer l'entité source"
}, },
"title": "Inverser 👻" "title": "Inverser 👻"
}, },
"user": { "user": {
"menu_options": { "menu_options": {
"binary_sensor": "Inverser un capteur binaire", "binary_sensor": "Inverser un capteur binaire",
"switch": "Inverser un commutateur" "switch": "Inverser un commutateur",
"valve": "Inverser une vanne",
"cover": "Inverser un ouvrant"
}, },
"title": "Inverser 👻", "title": "Inverser 👻",
"description": "Cette entrée permet d'inverser l'état d'une entité. Par exemple, inverser l'état ouvert/fermé ou allumé/éteint de capteurs binaires, ou de commutateurs." "description": "Cette entrée permet d'inverser l'état d'une entité. Par exemple, inverser l'état ouvert/fermé ou allumé/éteint de capteurs binaires, d'ouvrants, de commutateurs ou de vannes."
},
"cover": {
"data": {
"entity_id": "Entité source",
"hide_source": "Masquer l'entité source",
"inverse_position": "Inverser l'ouverture, la fermeture et la position",
"inverse_tilt": "Inverser l'inclinaison",
"name": "Nom"
},
"title": "Inverser 👻"
},
"valve": {
"title": "Inverser 👻",
"data": {
"hide_source": "Masquer l'entité source",
"entity_id": "Entité source",
"name": "Nom"
}
} }
} }
}, },
@@ -32,16 +52,34 @@
"binary_sensor": { "binary_sensor": {
"data": { "data": {
"name": "Nom", "name": "Nom",
"entity_id": "Entité d'origine", "entity_id": "Entité source",
"hide_source": "Cacher l'entité d'origine" "hide_source": "Masquer l'entité source"
}, },
"title": "Inverser 👻" "title": "Inverser 👻"
}, },
"switch": { "switch": {
"data": { "data": {
"hide_source": "Cacher l'entité d'origine", "hide_source": "Masquer l'entité source",
"name": "Nom", "name": "Nom",
"entity_id": "Entité d'origine" "entity_id": "Entité source"
},
"title": "Inverser 👻"
},
"cover": {
"data": {
"entity_id": "Entité source",
"name": "Nom",
"hide_source": "Masquer l'entité source",
"inverse_position": "Inverser l'ouverture, la fermeture et la position",
"inverse_tilt": "Inverser l'inclinaison"
},
"title": "Inverser 👻"
},
"valve": {
"data": {
"entity_id": "Entité source",
"hide_source": "Masquer l'entité source",
"name": "Nom"
}, },
"title": "Inverser 👻" "title": "Inverser 👻"
} }
@@ -1 +1,89 @@
{} {
"config": {
"step": {
"binary_sensor": {
"data": {
"entity_id": "Boarne-entiteit",
"hide_source": "Boarne-entiteit ferstopje",
"name": "Namme"
},
"title": "Omkeare 👻"
},
"cover": {
"data": {
"entity_id": "Boarne-entiteit",
"hide_source": "Boarne-entiteit ferstopje",
"inverse_position": "Iepenjen, sluten en posysje omkeare",
"inverse_tilt": "Kanteljen omkeare",
"name": "Namme"
},
"title": "Omkeare 👻"
},
"switch": {
"data": {
"entity_id": "Boarne-entiteit",
"hide_source": "Boarne-entiteit ferstopje",
"name": "Namme"
},
"title": "Omkeare 👻"
},
"valve": {
"data": {
"entity_id": "Boarne-entiteit",
"hide_source": "Boarne-entiteit ferstopje",
"name": "Namme"
},
"title": "Omkeare 👻"
},
"user": {
"description": "Mei dizze helper kinst do it gedrach fan in entiteit omkeare. Bygelyks iepen/ticht of oan/út omdraaie by binêre sensoren, bedekkingen, skeakelers en kleppen.",
"menu_options": {
"binary_sensor": "In binêre sensor omkeare",
"cover": "In bedekking omkeare",
"switch": "In skeakeler omkeare",
"valve": "In klep omkeare"
},
"title": "Omkeare 👻"
}
}
},
"options": {
"step": {
"binary_sensor": {
"data": {
"entity_id": "Boarne-entiteit",
"hide_source": "Boarne-entiteit ferstopje",
"name": "Namme"
},
"title": "Omkeare 👻"
},
"cover": {
"data": {
"entity_id": "Boarne-entiteit",
"hide_source": "Boarne-entiteit ferstopje",
"inverse_position": "Iepenjen, sluten en posysje omkeare",
"inverse_tilt": "Kanteljen omkeare",
"name": "Namme"
},
"title": "Omkeare 👻"
},
"switch": {
"data": {
"entity_id": "Boarne-entiteit",
"hide_source": "Boarne-entiteit ferstopje",
"name": "Namme"
},
"title": "Omkeare 👻"
},
"valve": {
"data": {
"entity_id": "Boarne-entiteit",
"hide_source": "Boarne-entiteit ferstopje",
"name": "Namme"
},
"title": "Omkeare 👻"
}
}
},
"title": "Omkeare 👻"
}
@@ -1 +1,89 @@
{} {
"config": {
"step": {
"binary_sensor": {
"data": {
"entity_id": "Aonán foinse",
"hide_source": "Folaigh an t-aonán foinse",
"name": "Ainm"
},
"title": "Inbhéartú 👻"
},
"cover": {
"data": {
"entity_id": "Aonán foinse",
"hide_source": "Folaigh an t-aonán foinse",
"inverse_position": "Inbhéartaigh oscailt, dúnadh agus suíomh",
"inverse_tilt": "Inbhéartaigh an claonadh",
"name": "Ainm"
},
"title": "Inbhéartú 👻"
},
"switch": {
"data": {
"entity_id": "Aonán foinse",
"hide_source": "Folaigh an t-aonán foinse",
"name": "Ainm"
},
"title": "Inbhéartú 👻"
},
"valve": {
"data": {
"entity_id": "Aonán foinse",
"hide_source": "Folaigh an t-aonán foinse",
"name": "Ainm"
},
"title": "Inbhéartú 👻"
},
"user": {
"description": "Ligeann an cúntóir seo duit iompar aonáin a inbhéartú. Mar shampla, oscailte/dúnta nó air/as a mhalartú do bhraiteoirí dénártha, do chlúdaigh, do lasca agus do chomhlaí.",
"menu_options": {
"binary_sensor": "Inbhéartaigh braiteoir dénártha",
"cover": "Inbhéartaigh clúdach",
"switch": "Inbhéartaigh lasc",
"valve": "Inbhéartaigh comhla"
},
"title": "Inbhéartú 👻"
}
}
},
"options": {
"step": {
"binary_sensor": {
"data": {
"entity_id": "Aonán foinse",
"hide_source": "Folaigh an t-aonán foinse",
"name": "Ainm"
},
"title": "Inbhéartú 👻"
},
"cover": {
"data": {
"entity_id": "Aonán foinse",
"hide_source": "Folaigh an t-aonán foinse",
"inverse_position": "Inbhéartaigh oscailt, dúnadh agus suíomh",
"inverse_tilt": "Inbhéartaigh an claonadh",
"name": "Ainm"
},
"title": "Inbhéartú 👻"
},
"switch": {
"data": {
"entity_id": "Aonán foinse",
"hide_source": "Folaigh an t-aonán foinse",
"name": "Ainm"
},
"title": "Inbhéartú 👻"
},
"valve": {
"data": {
"entity_id": "Aonán foinse",
"hide_source": "Folaigh an t-aonán foinse",
"name": "Ainm"
},
"title": "Inbhéartú 👻"
}
}
},
"title": "Inbhéartú 👻"
}
@@ -1 +1,89 @@
{} {
"config": {
"step": {
"binary_sensor": {
"data": {
"entity_id": "ישות מקור",
"hide_source": "הסתר ישות מקור",
"name": "שם"
},
"title": "היפוך 👻"
},
"cover": {
"data": {
"entity_id": "ישות מקור",
"hide_source": "הסתר ישות מקור",
"inverse_position": "הפוך פתיחה, סגירה ומיקום",
"inverse_tilt": "הפוך הטיה",
"name": "שם"
},
"title": "היפוך 👻"
},
"switch": {
"data": {
"entity_id": "ישות מקור",
"hide_source": "הסתר ישות מקור",
"name": "שם"
},
"title": "היפוך 👻"
},
"valve": {
"data": {
"entity_id": "ישות מקור",
"hide_source": "הסתר ישות מקור",
"name": "שם"
},
"title": "היפוך 👻"
},
"user": {
"description": "עוזר זה מאפשר להפוך את ההתנהגות של ישות. לדוגמה, להפוך את הפתיחה/סגירה או ההפעלה/כיבוי של חיישנים בינאריים, כיסויים, מתגים ושסתומים.",
"menu_options": {
"binary_sensor": "הפוך חיישן בינארי",
"cover": "הפוך כיסוי",
"switch": "הפוך מתג",
"valve": "הפוך שסתום"
},
"title": "היפוך 👻"
}
}
},
"options": {
"step": {
"binary_sensor": {
"data": {
"entity_id": "ישות מקור",
"hide_source": "הסתר ישות מקור",
"name": "שם"
},
"title": "היפוך 👻"
},
"cover": {
"data": {
"entity_id": "ישות מקור",
"hide_source": "הסתר ישות מקור",
"inverse_position": "הפוך פתיחה, סגירה ומיקום",
"inverse_tilt": "הפוך הטיה",
"name": "שם"
},
"title": "היפוך 👻"
},
"switch": {
"data": {
"entity_id": "ישות מקור",
"hide_source": "הסתר ישות מקור",
"name": "שם"
},
"title": "היפוך 👻"
},
"valve": {
"data": {
"entity_id": "ישות מקור",
"hide_source": "הסתר ישות מקור",
"name": "שם"
},
"title": "היפוך 👻"
}
}
},
"title": "היפוך 👻"
}
@@ -7,7 +7,17 @@
"hide_source": "Sembunyikan entitas sumber", "hide_source": "Sembunyikan entitas sumber",
"name": "Nama" "name": "Nama"
}, },
"title": "Kebalikannya 👻" "title": "Balikkan 👻"
},
"cover": {
"data": {
"entity_id": "Entitas sumber",
"hide_source": "Sembunyikan entitas sumber",
"inverse_position": "Balikkan pembukaan, penutupan, dan posisi",
"inverse_tilt": "Balikkan kemiringan",
"name": "Nama"
},
"title": "Balikkan 👻"
}, },
"switch": { "switch": {
"data": { "data": {
@@ -15,13 +25,23 @@
"hide_source": "Sembunyikan entitas sumber", "hide_source": "Sembunyikan entitas sumber",
"name": "Nama" "name": "Nama"
}, },
"title": "Inverse 👻" "title": "Balikkan 👻"
},
"valve": {
"data": {
"entity_id": "Entitas sumber",
"hide_source": "Sembunyikan entitas sumber",
"name": "Nama"
},
"title": "Balikkan 👻"
}, },
"user": { "user": {
"description": "Pembantu ini memungkinkan Anda untuk membalikkan perilaku suatu entitas. Misalnya, membalikkan buka/tutup atau hidup/mati sensor biner, dan sakelar.", "description": "Pembantu ini memungkinkan Anda membalikkan perilaku sebuah entitas. Misalnya, membalikkan buka/tutup atau nyala/mati pada sensor biner, penutup, sakelar, dan katup.",
"menu_options": { "menu_options": {
"binary_sensor": "Balikkan sensor biner", "binary_sensor": "Balikkan sensor biner",
"switch": "Balikkan sakelar" "cover": "Balikkan penutup",
"switch": "Balikkan sakelar",
"valve": "Balikkan katup"
}, },
"title": "Balikkan 👻" "title": "Balikkan 👻"
} }
@@ -35,7 +55,17 @@
"hide_source": "Sembunyikan entitas sumber", "hide_source": "Sembunyikan entitas sumber",
"name": "Nama" "name": "Nama"
}, },
"title": "Kebalikannya 👻" "title": "Balikkan 👻"
},
"cover": {
"data": {
"entity_id": "Entitas sumber",
"hide_source": "Sembunyikan entitas sumber",
"inverse_position": "Balikkan pembukaan, penutupan, dan posisi",
"inverse_tilt": "Balikkan kemiringan",
"name": "Nama"
},
"title": "Balikkan 👻"
}, },
"switch": { "switch": {
"data": { "data": {
@@ -43,9 +73,17 @@
"hide_source": "Sembunyikan entitas sumber", "hide_source": "Sembunyikan entitas sumber",
"name": "Nama" "name": "Nama"
}, },
"title": "Kebalikannya 👻" "title": "Balikkan 👻"
},
"valve": {
"data": {
"entity_id": "Entitas sumber",
"hide_source": "Sembunyikan entitas sumber",
"name": "Nama"
},
"title": "Balikkan 👻"
} }
} }
}, },
"title": "Kebalikannya 👻" "title": "Balikkan 👻"
} }
@@ -9,6 +9,16 @@
}, },
"title": "Inverso 👻" "title": "Inverso 👻"
}, },
"cover": {
"data": {
"entity_id": "Entità sorgente",
"hide_source": "Nascondi entità sorgente",
"inverse_position": "Inverti apertura, chiusura e posizione",
"inverse_tilt": "Inverti inclinazione",
"name": "Nome"
},
"title": "Inverso 👻"
},
"switch": { "switch": {
"data": { "data": {
"entity_id": "Entità sorgente", "entity_id": "Entità sorgente",
@@ -17,11 +27,21 @@
}, },
"title": "Inverso 👻" "title": "Inverso 👻"
}, },
"valve": {
"data": {
"entity_id": "Entità sorgente",
"hide_source": "Nascondi entità sorgente",
"name": "Nome"
},
"title": "Inverso 👻"
},
"user": { "user": {
"description": "Questo aiutante ti permette di invertire il comportamento di un'entità. Ad esempio, apri/chiudi o accendi/spegni per un binary_sensor o uno switch", "description": "Questo helper ti permette di invertire il comportamento di un'entità. Per esempio, inverti aperto/chiuso o acceso/spento di sensori binari, coperture, interruttori e valvole.",
"menu_options": { "menu_options": {
"binary_sensor": "Inverti un binary_sensor", "binary_sensor": "Inverti un sensore binario",
"switch": "Inverti uno switch" "cover": "Inverti una copertura",
"switch": "Inverti un interruttore",
"valve": "Inverti una valvola"
}, },
"title": "Inverso 👻" "title": "Inverso 👻"
} }
@@ -37,6 +57,14 @@
}, },
"title": "Inverso 👻" "title": "Inverso 👻"
}, },
"valve": {
"data": {
"entity_id": "Entità sorgente",
"hide_source": "Nascondi entità sorgente",
"name": "Nome"
},
"title": "Inverso 👻"
},
"binary_sensor": { "binary_sensor": {
"data": { "data": {
"entity_id": "Entità sorgente", "entity_id": "Entità sorgente",
@@ -44,6 +72,16 @@
"name": "Nome" "name": "Nome"
}, },
"title": "Inverso 👻" "title": "Inverso 👻"
},
"cover": {
"data": {
"entity_id": "Entità sorgente",
"hide_source": "Nascondi entità sorgente",
"inverse_position": "Inverti apertura, chiusura e posizione",
"inverse_tilt": "Inverti inclinazione",
"name": "Nome"
},
"title": "Inverso 👻"
} }
} }
}, },
@@ -1 +1,89 @@
{} {
"config": {
"step": {
"binary_sensor": {
"data": {
"entity_id": "ソースエンティティ",
"hide_source": "ソースエンティティを非表示にする",
"name": "名前"
},
"title": "反転 👻"
},
"cover": {
"data": {
"entity_id": "ソースエンティティ",
"hide_source": "ソースエンティティを非表示にする",
"inverse_position": "開く・閉じる動作と位置を反転",
"inverse_tilt": "チルトを反転",
"name": "名前"
},
"title": "反転 👻"
},
"switch": {
"data": {
"entity_id": "ソースエンティティ",
"hide_source": "ソースエンティティを非表示にする",
"name": "名前"
},
"title": "反転 👻"
},
"valve": {
"data": {
"entity_id": "ソースエンティティ",
"hide_source": "ソースエンティティを非表示にする",
"name": "名前"
},
"title": "反転 👻"
},
"user": {
"description": "このヘルパーは、エンティティの動作を反転させます。たとえば、バイナリセンサー、カバー、スイッチ、バルブの開/閉やオン/オフを逆にします。",
"menu_options": {
"binary_sensor": "バイナリセンサーを反転",
"cover": "カバーを反転",
"switch": "スイッチを反転",
"valve": "バルブを反転"
},
"title": "反転 👻"
}
}
},
"options": {
"step": {
"binary_sensor": {
"data": {
"entity_id": "ソースエンティティ",
"hide_source": "ソースエンティティを非表示にする",
"name": "名前"
},
"title": "反転 👻"
},
"cover": {
"data": {
"entity_id": "ソースエンティティ",
"hide_source": "ソースエンティティを非表示にする",
"inverse_position": "開く・閉じる動作と位置を反転",
"inverse_tilt": "チルトを反転",
"name": "名前"
},
"title": "反転 👻"
},
"switch": {
"data": {
"entity_id": "ソースエンティティ",
"hide_source": "ソースエンティティを非表示にする",
"name": "名前"
},
"title": "反転 👻"
},
"valve": {
"data": {
"entity_id": "ソースエンティティ",
"hide_source": "ソースエンティティを非表示にする",
"name": "名前"
},
"title": "反転 👻"
}
}
},
"title": "反転 👻"
}
@@ -3,8 +3,18 @@
"step": { "step": {
"binary_sensor": { "binary_sensor": {
"data": { "data": {
"entity_id": "출처 구성요소", "entity_id": "소스 엔티티",
"hide_source": "출처 구성요소 숨김", "hide_source": "소스 엔티티 숨기기",
"name": "이름"
},
"title": "반전 👻"
},
"cover": {
"data": {
"entity_id": "소스 엔티티",
"hide_source": "소스 엔티티 숨기기",
"inverse_position": "열림, 닫힘 및 위치 반전",
"inverse_tilt": "기울기 반전",
"name": "이름" "name": "이름"
}, },
"title": "반전 👻" "title": "반전 👻"
@@ -12,16 +22,26 @@
"switch": { "switch": {
"data": { "data": {
"name": "이름", "name": "이름",
"entity_id": "출처 구성요소", "entity_id": "소스 엔티티",
"hide_source": "출처 구성요소 숨김" "hide_source": "소스 엔티티 숨기기"
},
"title": "반전 👻"
},
"valve": {
"data": {
"entity_id": "소스 엔티티",
"hide_source": "소스 엔티티 숨기기",
"name": "이름"
}, },
"title": "반전 👻" "title": "반전 👻"
}, },
"user": { "user": {
"description": "이 도우미는 구성요소의 동작을 반전시키는 데 도움이 됩니다. 예를 들어, 바이너리 센서 및 스위치의 열림/닫힘 또는 켜짐/꺼짐을 반전시킵니다.", "description": "이 도우미는 엔티티의 동작을 반전시킵니다. 예를 들어 이진 센서, 여닫이, 스위치, 밸브의 열림/닫힘이나 켜짐/꺼짐을 뒤집습니다.",
"menu_options": { "menu_options": {
"switch": "스위치 반전", "switch": "스위치 반전",
"binary_sensor": "이진 센서 반전" "valve": "밸브 반전",
"binary_sensor": "이진 센서 반전",
"cover": "여닫이 반전"
}, },
"title": "반전 👻" "title": "반전 👻"
} }
@@ -31,8 +51,18 @@
"step": { "step": {
"binary_sensor": { "binary_sensor": {
"data": { "data": {
"hide_source": "출처 구성요소 숨김", "hide_source": "소스 엔티티 숨기기",
"entity_id": "출처 구성요소", "entity_id": "소스 엔티티",
"name": "이름"
},
"title": "반전 👻"
},
"cover": {
"data": {
"entity_id": "소스 엔티티",
"hide_source": "소스 엔티티 숨기기",
"inverse_position": "열림, 닫힘 및 위치 반전",
"inverse_tilt": "기울기 반전",
"name": "이름" "name": "이름"
}, },
"title": "반전 👻" "title": "반전 👻"
@@ -40,8 +70,16 @@
"switch": { "switch": {
"data": { "data": {
"name": "이름", "name": "이름",
"entity_id": "출처 구성요소", "entity_id": "소스 엔티티",
"hide_source": "출처 구성요소 숨김" "hide_source": "소스 엔티티 숨기기"
},
"title": "반전 👻"
},
"valve": {
"data": {
"entity_id": "소스 엔티티",
"hide_source": "소스 엔티티 숨기기",
"name": "이름"
}, },
"title": "반전 👻" "title": "반전 👻"
} }
@@ -4,26 +4,46 @@
"binary_sensor": { "binary_sensor": {
"data": { "data": {
"name": "Pavadinimas", "name": "Pavadinimas",
"entity_id": "Pirminis objektas", "entity_id": "Šaltinio subjektas",
"hide_source": "Slėpti pirminį objektą" "hide_source": "Slėpti šaltinio subjektą"
},
"title": "Inversija 👻"
},
"cover": {
"data": {
"entity_id": "Šaltinio subjektas",
"hide_source": "Slėpti šaltinio subjektą",
"inverse_position": "Invertuoti atidarymą, uždarymą ir padėtį",
"inverse_tilt": "Invertuoti pakreipimą",
"name": "Pavadinimas"
}, },
"title": "Inversija 👻" "title": "Inversija 👻"
}, },
"switch": { "switch": {
"data": { "data": {
"name": "Pavadinimas", "name": "Pavadinimas",
"entity_id": "Pirminis objektas", "entity_id": "Šaltinio subjektas",
"hide_source": "Slėpti pirminį objektą" "hide_source": "Slėpti šaltinio subjektą"
},
"title": "Inversija 👻"
},
"valve": {
"data": {
"entity_id": "Šaltinio subjektas",
"hide_source": "Slėpti šaltinio subjektą",
"name": "Pavadinimas"
}, },
"title": "Inversija 👻" "title": "Inversija 👻"
}, },
"user": { "user": {
"menu_options": { "menu_options": {
"binary_sensor": "Invertuoti dvejetainio jutiklio būseną", "binary_sensor": "Invertuoti dvejetainio jutiklio būseną",
"switch": "Invertuoti jungiklį" "cover": "Invertuoti uždangą",
"switch": "Invertuoti jungiklį",
"valve": "Invertuoti vožtuvą"
}, },
"title": "Inversija 👻", "title": "Inversija 👻",
"description": "Šis pagalbininkas leidžia pakeisti esamą objekto elgseną į priešingą. Pavyzdžiui, galima apversti dvejetainio jutiklio ar jungiklio būseną – atidaryta/uždaryta arba įjungta/išjungta." "description": "Šis pagalbininkas leidžia invertuoti subjekto elgseną. Pavyzdžiui, sukeisti atidaryta/uždaryta arba įjungta/išjungta dvejetainiams jutikliams, uždangoms, jungikliams ir vožtuvams."
} }
} }
}, },
@@ -32,15 +52,33 @@
"binary_sensor": { "binary_sensor": {
"data": { "data": {
"name": "Pavadinimas", "name": "Pavadinimas",
"entity_id": "Pirminis objektas", "entity_id": "Šaltinio subjektas",
"hide_source": "Slėpti pirminį objektą" "hide_source": "Slėpti šaltinio subjektą"
},
"title": "Inversija 👻"
},
"cover": {
"data": {
"entity_id": "Šaltinio subjektas",
"hide_source": "Slėpti šaltinio subjektą",
"inverse_position": "Invertuoti atidarymą, uždarymą ir padėtį",
"inverse_tilt": "Invertuoti pakreipimą",
"name": "Pavadinimas"
}, },
"title": "Inversija 👻" "title": "Inversija 👻"
}, },
"switch": { "switch": {
"data": { "data": {
"entity_id": "Pirminis objektas", "entity_id": "Šaltinio subjektas",
"hide_source": "Slėpti pirminį objektą", "hide_source": "Slėpti šaltinio subjektą",
"name": "Pavadinimas"
},
"title": "Inversija 👻"
},
"valve": {
"data": {
"entity_id": "Šaltinio subjektas",
"hide_source": "Slėpti šaltinio subjektą",
"name": "Pavadinimas" "name": "Pavadinimas"
}, },
"title": "Inversija 👻" "title": "Inversija 👻"
@@ -1 +1,89 @@
{} {
"config": {
"step": {
"binary_sensor": {
"data": {
"entity_id": "Изворен ентитет",
"hide_source": "Сокриј го изворниот ентитет",
"name": "Име"
},
"title": "Инверзија 👻"
},
"cover": {
"data": {
"entity_id": "Изворен ентитет",
"hide_source": "Сокриј го изворниот ентитет",
"inverse_position": "Инвертирај отворање, затворање и позиција",
"inverse_tilt": "Инвертирај наклон",
"name": "Име"
},
"title": "Инверзија 👻"
},
"switch": {
"data": {
"entity_id": "Изворен ентитет",
"hide_source": "Сокриј го изворниот ентитет",
"name": "Име"
},
"title": "Инверзија 👻"
},
"valve": {
"data": {
"entity_id": "Изворен ентитет",
"hide_source": "Сокриј го изворниот ентитет",
"name": "Име"
},
"title": "Инверзија 👻"
},
"user": {
"description": "Овој помошник ви овозможува да го инвертирате однесувањето на ентитет. На пример, да ги замените отворено/затворено или вклучено/исклучено кај бинарни сензори, ролетни, прекинувачи и вентили.",
"menu_options": {
"binary_sensor": "Инвертирај бинарен сензор",
"cover": "Инвертирај ролетна",
"switch": "Инвертирај прекинувач",
"valve": "Инвертирај вентил"
},
"title": "Инверзија 👻"
}
}
},
"options": {
"step": {
"binary_sensor": {
"data": {
"entity_id": "Изворен ентитет",
"hide_source": "Сокриј го изворниот ентитет",
"name": "Име"
},
"title": "Инверзија 👻"
},
"cover": {
"data": {
"entity_id": "Изворен ентитет",
"hide_source": "Сокриј го изворниот ентитет",
"inverse_position": "Инвертирај отворање, затворање и позиција",
"inverse_tilt": "Инвертирај наклон",
"name": "Име"
},
"title": "Инверзија 👻"
},
"switch": {
"data": {
"entity_id": "Изворен ентитет",
"hide_source": "Сокриј го изворниот ентитет",
"name": "Име"
},
"title": "Инверзија 👻"
},
"valve": {
"data": {
"entity_id": "Изворен ентитет",
"hide_source": "Сокриј го изворниот ентитет",
"name": "Име"
},
"title": "Инверзија 👻"
}
}
},
"title": "Инверзија 👻"
}

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