Updated apps
This commit is contained in:
@@ -0,0 +1 @@
|
||||
"""Spook - Your homie."""
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,40 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import area_registry as ar, config_validation as cv
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant service to add an alias to an area."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "add_alias_to_area"
|
||||
schema = {
|
||||
vol.Required("area_id"): cv.string,
|
||||
vol.Required("alias"): vol.All(cv.ensure_list, [cv.string]),
|
||||
}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
area_registry = ar.async_get(self.hass)
|
||||
if not (area := area_registry.async_get_area(call.data["area_id"])):
|
||||
msg = f"Area {call.data['area_id']} not found"
|
||||
raise HomeAssistantError(msg)
|
||||
|
||||
aliases = area.aliases.copy()
|
||||
area_registry.async_update(
|
||||
call.data["area_id"],
|
||||
aliases=aliases.union(call.data["alias"]),
|
||||
)
|
||||
@@ -0,0 +1,43 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import (
|
||||
config_validation as cv,
|
||||
floor_registry as fr,
|
||||
)
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant service to add an alias to a floor."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "add_alias_to_floor"
|
||||
schema = {
|
||||
vol.Required("floor_id"): cv.string,
|
||||
vol.Required("alias"): vol.All(cv.ensure_list, [cv.string]),
|
||||
}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
floor_registry = fr.async_get(self.hass)
|
||||
if not (floor := floor_registry.async_get_floor(call.data["floor_id"])):
|
||||
msg = f"Floor {call.data['floor_id']} not found"
|
||||
raise HomeAssistantError(msg)
|
||||
|
||||
aliases = floor.aliases.copy()
|
||||
floor_registry.async_update(
|
||||
call.data["floor_id"],
|
||||
aliases=aliases.union(call.data["alias"]),
|
||||
)
|
||||
@@ -0,0 +1,45 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import (
|
||||
area_registry as ar,
|
||||
config_validation as cv,
|
||||
floor_registry as fr,
|
||||
)
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant service to add an area to a floor."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "add_area_to_floor"
|
||||
schema = {
|
||||
vol.Required("floor_id"): cv.string,
|
||||
vol.Required("area_id"): vol.All(cv.ensure_list, [cv.string]),
|
||||
}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
floor_registry = fr.async_get(self.hass)
|
||||
if not floor_registry.async_get_floor(call.data["floor_id"]):
|
||||
msg = f"Floor {call.data['floor_id']} not found"
|
||||
raise HomeAssistantError(msg)
|
||||
|
||||
area_registry = ar.async_get(self.hass)
|
||||
for area_id in call.data["area_id"]:
|
||||
area_registry.async_update(
|
||||
area_id=area_id,
|
||||
floor_id=call.data["floor_id"],
|
||||
)
|
||||
@@ -0,0 +1,45 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import (
|
||||
area_registry as ar,
|
||||
config_validation as cv,
|
||||
device_registry as dr,
|
||||
)
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant service to add a device to an area."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "add_device_to_area"
|
||||
schema = {
|
||||
vol.Required("area_id"): cv.string,
|
||||
vol.Required("device_id"): vol.All(cv.ensure_list, [cv.string]),
|
||||
}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
area_registry = ar.async_get(self.hass)
|
||||
if not area_registry.async_get_area(call.data["area_id"]):
|
||||
msg = f"Area {call.data['area_id']} not found"
|
||||
raise HomeAssistantError(msg)
|
||||
|
||||
device_registry = dr.async_get(self.hass)
|
||||
for device_id in call.data["device_id"]:
|
||||
device_registry.async_update_device(
|
||||
device_id,
|
||||
area_id=call.data["area_id"],
|
||||
)
|
||||
@@ -0,0 +1,45 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import (
|
||||
area_registry as ar,
|
||||
config_validation as cv,
|
||||
entity_registry as er,
|
||||
)
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant service to add a entity to an area."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "add_entity_to_area"
|
||||
schema = {
|
||||
vol.Required("area_id"): cv.string,
|
||||
vol.Required("entity_id"): vol.All(cv.ensure_list, [cv.string]),
|
||||
}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
area_registry = ar.async_get(self.hass)
|
||||
if not area_registry.async_get_area(call.data["area_id"]):
|
||||
msg = f"Area {call.data['area_id']} not found"
|
||||
raise HomeAssistantError(msg)
|
||||
|
||||
entity_registry = er.async_get(self.hass)
|
||||
for entity_id in call.data["entity_id"]:
|
||||
entity_registry.async_update_entity(
|
||||
entity_id,
|
||||
area_id=call.data["area_id"],
|
||||
)
|
||||
@@ -0,0 +1,46 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import (
|
||||
area_registry as ar,
|
||||
config_validation as cv,
|
||||
label_registry as lr,
|
||||
)
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant service to add a label to an area."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "add_label_to_area"
|
||||
schema = {
|
||||
vol.Required("label_id"): vol.All(cv.ensure_list, [cv.string]),
|
||||
vol.Required("area_id"): vol.All(cv.ensure_list, [cv.string]),
|
||||
}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
label_registry = lr.async_get(self.hass)
|
||||
for label_id in call.data["label_id"]:
|
||||
if not label_registry.async_get_label(label_id):
|
||||
msg = f"Label {label_id} not found"
|
||||
raise HomeAssistantError(msg)
|
||||
|
||||
area_registry = ar.async_get(self.hass)
|
||||
for area_id in call.data["area_id"]:
|
||||
if area_entry := area_registry.async_get_area(area_id):
|
||||
labels = area_entry.labels.copy()
|
||||
labels.update(call.data["label_id"])
|
||||
area_registry.async_update(area_id, labels=labels)
|
||||
@@ -0,0 +1,46 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import (
|
||||
config_validation as cv,
|
||||
device_registry as dr,
|
||||
label_registry as lr,
|
||||
)
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant service to add a label to a device."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "add_label_to_device"
|
||||
schema = {
|
||||
vol.Required("label_id"): vol.All(cv.ensure_list, [cv.string]),
|
||||
vol.Required("device_id"): vol.All(cv.ensure_list, [cv.string]),
|
||||
}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
label_registry = lr.async_get(self.hass)
|
||||
for label_id in call.data["label_id"]:
|
||||
if not label_registry.async_get_label(label_id):
|
||||
msg = f"Label {label_id} not found"
|
||||
raise HomeAssistantError(msg)
|
||||
|
||||
device_registry = dr.async_get(self.hass)
|
||||
for device_id in call.data["device_id"]:
|
||||
if device_entry := device_registry.async_get(device_id):
|
||||
labels = device_entry.labels.copy()
|
||||
labels.update(call.data["label_id"])
|
||||
device_registry.async_update_device(device_id, labels=labels)
|
||||
@@ -0,0 +1,46 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import (
|
||||
config_validation as cv,
|
||||
entity_registry as er,
|
||||
label_registry as lr,
|
||||
)
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant service to add a label to an entity."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "add_label_to_entity"
|
||||
schema = {
|
||||
vol.Required("label_id"): vol.All(cv.ensure_list, [cv.string]),
|
||||
vol.Required("entity_id"): vol.All(cv.ensure_list, [cv.string]),
|
||||
}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
label_registry = lr.async_get(self.hass)
|
||||
for label_id in call.data["label_id"]:
|
||||
if not label_registry.async_get_label(label_id):
|
||||
msg = f"Label {label_id} not found"
|
||||
raise HomeAssistantError(msg)
|
||||
|
||||
entity_registry = er.async_get(self.hass)
|
||||
for entity_id in call.data["entity_id"]:
|
||||
if entity_entry := entity_registry.async_get(entity_id):
|
||||
labels = entity_entry.labels.copy()
|
||||
labels.update(call.data["label_id"])
|
||||
entity_registry.async_update_entity(entity_id, labels=labels)
|
||||
@@ -0,0 +1,36 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.helpers import area_registry as ar, config_validation as cv
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant area service to create areas on the fly."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "create_area"
|
||||
schema = {
|
||||
vol.Required("name"): cv.string,
|
||||
vol.Optional("aliases"): [cv.string],
|
||||
vol.Optional("icon"): cv.icon,
|
||||
}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
area_registry = ar.async_get(self.hass)
|
||||
area_registry.async_create(
|
||||
name=call.data["name"],
|
||||
aliases=call.data.get("aliases"),
|
||||
icon=call.data.get("icon"),
|
||||
)
|
||||
@@ -0,0 +1,38 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.helpers import config_validation as cv, floor_registry as fr
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant floor service to create floors on the fly."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "create_floor"
|
||||
schema = {
|
||||
vol.Required("name"): cv.string,
|
||||
vol.Optional("aliases"): [cv.string],
|
||||
vol.Optional("icon"): cv.icon,
|
||||
vol.Optional("level"): vol.Coerce(int),
|
||||
}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
floor_registry = fr.async_get(self.hass)
|
||||
floor_registry.async_create(
|
||||
name=call.data["name"],
|
||||
aliases=call.data.get("aliases"),
|
||||
icon=call.data.get("icon"),
|
||||
level=call.data.get("level"),
|
||||
)
|
||||
@@ -0,0 +1,69 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.helpers import config_validation as cv, label_registry as lr
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
SUPPORTED_LABEL_THEME_COLORS = {
|
||||
"primary",
|
||||
"accent",
|
||||
"disabled",
|
||||
"amber",
|
||||
"black",
|
||||
"blue-grey",
|
||||
"blue",
|
||||
"brown",
|
||||
"cyan",
|
||||
"dark-grey",
|
||||
"deep-orange",
|
||||
"deep-purple",
|
||||
"green",
|
||||
"grey",
|
||||
"indigo",
|
||||
"light-blue",
|
||||
"light-green",
|
||||
"light-grey",
|
||||
"lime",
|
||||
"orange",
|
||||
"pink",
|
||||
"purple",
|
||||
"red",
|
||||
"teal",
|
||||
"white",
|
||||
"yellow",
|
||||
}
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant service to create labels on the fly."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "create_label"
|
||||
schema = {
|
||||
vol.Required("name"): cv.string,
|
||||
vol.Optional("color"): vol.Any(
|
||||
cv.color_hex, vol.In(SUPPORTED_LABEL_THEME_COLORS)
|
||||
),
|
||||
vol.Optional("description"): cv.string,
|
||||
vol.Optional("icon"): cv.icon,
|
||||
}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
label_registry = lr.async_get(self.hass)
|
||||
label_registry.async_create(
|
||||
name=call.data["name"],
|
||||
color=call.data.get("color"),
|
||||
description=call.data.get("description"),
|
||||
icon=call.data.get("icon"),
|
||||
)
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.const import ATTR_RESTORED
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant Core integration service to delete all orphaned entities."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "delete_all_orphaned_entities"
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
entity_registry = er.async_get(self.hass)
|
||||
for state in self.hass.states.async_all():
|
||||
if not state.attributes.get(ATTR_RESTORED):
|
||||
continue
|
||||
entity_registry.async_remove(state.entity_id)
|
||||
self.hass.states.async_remove(state.entity_id, call.context)
|
||||
@@ -0,0 +1,28 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.helpers import area_registry as ar, config_validation as cv
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant area service to delete areas on the fly."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "delete_area"
|
||||
schema = {vol.Required("area_id"): cv.string}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
area_registry = ar.async_get(self.hass)
|
||||
area_registry.async_delete(call.data["area_id"])
|
||||
@@ -0,0 +1,28 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.helpers import config_validation as cv, floor_registry as fr
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant floor service to delete floors on the fly."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "delete_floor"
|
||||
schema = {vol.Required("floor_id"): cv.string}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
floor_registry = fr.async_get(self.hass)
|
||||
floor_registry.async_delete(call.data["floor_id"])
|
||||
@@ -0,0 +1,28 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.helpers import config_validation as cv, label_registry as lr
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant service to delete labels on the fly."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "delete_label"
|
||||
schema = {vol.Required("label_id"): cv.string}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
label_registry = lr.async_get(self.hass)
|
||||
label_registry.async_delete(call.data["label_id"])
|
||||
@@ -0,0 +1,32 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.config_entries import ConfigEntryDisabler
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant Core integration service to disable a config entry."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "disable_config_entry"
|
||||
schema = {vol.Required("config_entry_id"): vol.All(cv.ensure_list, [cv.string])}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
for config_entry_id in call.data["config_entry_id"]:
|
||||
await self.hass.config_entries.async_set_disabled_by(
|
||||
config_entry_id,
|
||||
disabled_by=ConfigEntryDisabler.USER,
|
||||
)
|
||||
@@ -0,0 +1,30 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.helpers import config_validation as cv, device_registry as dr
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
from ..device import async_disable_device_and_parent_if_needed
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant Core integration service to disable a device."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "disable_device"
|
||||
schema = {vol.Required("device_id"): vol.All(cv.ensure_list, [cv.string])}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
device_registry = dr.async_get(self.hass)
|
||||
for device_id in call.data["device_id"]:
|
||||
async_disable_device_and_parent_if_needed(device_registry, device_id)
|
||||
@@ -0,0 +1,32 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant Core integration service to disable an entity."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "disable_entity"
|
||||
schema = {vol.Required("entity_id"): vol.All(cv.ensure_list, [cv.string])}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
entity_registry = er.async_get(self.hass)
|
||||
for entity_id in call.data["entity_id"]:
|
||||
entity_registry.async_update_entity(
|
||||
entity_id=entity_id,
|
||||
disabled_by=er.RegistryEntryDisabler.USER,
|
||||
)
|
||||
@@ -0,0 +1,39 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant Core integration service to disable polling."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "disable_polling"
|
||||
schema = {vol.Required("config_entry_id"): cv.string}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
if not (
|
||||
entry := self.hass.config_entries.async_get_entry(
|
||||
call.data["config_entry_id"],
|
||||
)
|
||||
):
|
||||
msg = f"Config entry not found: {call.data['config_entry_id']}"
|
||||
raise HomeAssistantError(msg)
|
||||
|
||||
self.hass.config_entries.async_update_entry(
|
||||
entry,
|
||||
pref_disable_polling=True,
|
||||
)
|
||||
@@ -0,0 +1,36 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant Core integration service to disable a user."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "disable_user"
|
||||
schema = {vol.Required("user_id"): vol.All(cv.ensure_list, [cv.string])}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
for user_id in call.data["user_id"]:
|
||||
user = await self.hass.auth.async_get_user(user_id)
|
||||
if user is None:
|
||||
message = f"Could not find user: {user_id}"
|
||||
raise HomeAssistantError(message)
|
||||
if user.system_generated:
|
||||
message = f"Cannot disable a system-generated user: {user_id}"
|
||||
raise HomeAssistantError(message)
|
||||
await self.hass.auth.async_update_user(user, is_active=False)
|
||||
@@ -0,0 +1,31 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant Core integration service to enable a config entry."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "enable_config_entry"
|
||||
schema = {vol.Required("config_entry_id"): vol.All(cv.ensure_list, [cv.string])}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
for config_entry_id in call.data["config_entry_id"]:
|
||||
await self.hass.config_entries.async_set_disabled_by(
|
||||
config_entry_id,
|
||||
disabled_by=None,
|
||||
)
|
||||
@@ -0,0 +1,30 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.helpers import config_validation as cv, device_registry as dr
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
from ..device import async_enable_device_and_parent
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant Core integration service to enable a device."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "enable_device"
|
||||
schema = {vol.Required("device_id"): vol.All(cv.ensure_list, [cv.string])}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
device_registry = dr.async_get(self.hass)
|
||||
for device_id in call.data["device_id"]:
|
||||
async_enable_device_and_parent(device_registry, device_id)
|
||||
@@ -0,0 +1,32 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant Core integration service to enable an entity."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "enable_entity"
|
||||
schema = {vol.Required("entity_id"): vol.All(cv.ensure_list, [cv.string])}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
entity_registry = er.async_get(self.hass)
|
||||
for entity_id in call.data["entity_id"]:
|
||||
entity_registry.async_update_entity(
|
||||
entity_id=entity_id,
|
||||
disabled_by=None,
|
||||
)
|
||||
@@ -0,0 +1,39 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant Core integration service to enable polling."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "enable_polling"
|
||||
schema = {vol.Required("config_entry_id"): cv.string}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
if not (
|
||||
entry := self.hass.config_entries.async_get_entry(
|
||||
call.data["config_entry_id"],
|
||||
)
|
||||
):
|
||||
msg = f"Config entry not found: {call.data['config_entry_id']}"
|
||||
raise HomeAssistantError(msg)
|
||||
|
||||
self.hass.config_entries.async_update_entry(
|
||||
entry,
|
||||
pref_disable_polling=False,
|
||||
)
|
||||
@@ -0,0 +1,36 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant Core integration service to enable a user."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "enable_user"
|
||||
schema = {vol.Required("user_id"): vol.All(cv.ensure_list, [cv.string])}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
for user_id in call.data["user_id"]:
|
||||
user = await self.hass.auth.async_get_user(user_id)
|
||||
if user is None:
|
||||
message = f"Could not find user: {user_id}"
|
||||
raise HomeAssistantError(message)
|
||||
if user.system_generated:
|
||||
message = f"Cannot enable a system-generated user: {user_id}"
|
||||
raise HomeAssistantError(message)
|
||||
await self.hass.auth.async_update_user(user, is_active=True)
|
||||
@@ -0,0 +1,33 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant Core integration service to hide an entity."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "hide_entity"
|
||||
admin = True
|
||||
schema = {vol.Required("entity_id"): vol.All(cv.ensure_list, [cv.string])}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
entity_registry = er.async_get(self.hass)
|
||||
for entity_id in call.data["entity_id"]:
|
||||
entity_registry.async_update_entity(
|
||||
entity_id=entity_id,
|
||||
hidden_by=er.RegistryEntryHider.USER,
|
||||
)
|
||||
@@ -0,0 +1,76 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.config_entries import DISCOVERY_SOURCES, SOURCE_IGNORE
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.translation import async_get_translations
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant Core integration service to ignore all discovered devices."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "ignore_all_discovered"
|
||||
schema = {vol.Optional("domain"): vol.All(cv.ensure_list, [cv.string])}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
flows_to_ignore = [
|
||||
flow
|
||||
for flow in self.hass.config_entries.flow.async_progress()
|
||||
if (
|
||||
"context" in flow
|
||||
and "source" in flow["context"]
|
||||
and flow["context"]["source"] in DISCOVERY_SOURCES
|
||||
and (
|
||||
"domain" not in call.data or flow["handler"] in call.data["domain"]
|
||||
)
|
||||
)
|
||||
]
|
||||
|
||||
translations = await async_get_translations(
|
||||
self.hass,
|
||||
"en",
|
||||
"config_flow",
|
||||
integrations=(flow["handler"] for flow in flows_to_ignore),
|
||||
config_flow=True,
|
||||
)
|
||||
|
||||
tasks = []
|
||||
for flow in flows_to_ignore:
|
||||
title = "Ignored by Spook"
|
||||
if flow_title := translations.get(
|
||||
f"component.{flow['handler']}.config.flow_title",
|
||||
):
|
||||
title = flow_title.format(**flow["context"]["title_placeholders"])
|
||||
elif (
|
||||
"title_placeholders" in flow["context"]
|
||||
and "name" in flow["context"]["title_placeholders"]
|
||||
):
|
||||
title = flow["context"]["title_placeholders"]["name"]
|
||||
|
||||
tasks.append(
|
||||
self.hass.config_entries.flow.async_init(
|
||||
flow["handler"],
|
||||
context={"source": SOURCE_IGNORE},
|
||||
data={
|
||||
"unique_id": flow["context"]["unique_id"],
|
||||
"title": f"{title} 👻",
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
if tasks:
|
||||
await asyncio.gather(*tasks)
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import create_engine, text
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.components.recorder import (
|
||||
get_instance,
|
||||
)
|
||||
from homeassistant.core import ServiceResponse, SupportsResponse
|
||||
|
||||
from ....services import AbstractSpookService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookService):
|
||||
"""Home Assistant Core integration service to list all orphaned database entities."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "list_orphaned_database_entities"
|
||||
supports_response = SupportsResponse.ONLY
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> ServiceResponse:
|
||||
"""Handle the service call."""
|
||||
query = text(
|
||||
"""
|
||||
SELECT DISTINCT(entity_id) FROM states_meta
|
||||
"""
|
||||
)
|
||||
db_url = get_instance(self.hass).db_url
|
||||
engine = create_engine(db_url)
|
||||
with engine.connect() as conn:
|
||||
response = conn.execute(query)
|
||||
db_list = [e[0] for e in response]
|
||||
states_list = self.hass.states.async_entity_ids()
|
||||
compared_list = set(db_list).difference(states_list)
|
||||
if call.return_response:
|
||||
return {
|
||||
"count": len(compared_list),
|
||||
"entities": list(compared_list),
|
||||
}
|
||||
return None
|
||||
@@ -0,0 +1,40 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import area_registry as ar, config_validation as cv
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant service to remove an alias to an area."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "remove_alias_from_area"
|
||||
schema = {
|
||||
vol.Required("area_id"): cv.string,
|
||||
vol.Required("alias"): vol.All(cv.ensure_list, [cv.string]),
|
||||
}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
area_registry = ar.async_get(self.hass)
|
||||
if not (area := area_registry.async_get_area(call.data["area_id"])):
|
||||
msg = f"Area {call.data['area_id']} not found"
|
||||
raise HomeAssistantError(msg)
|
||||
|
||||
aliases = area.aliases.copy()
|
||||
area_registry.async_update(
|
||||
call.data["area_id"],
|
||||
aliases=aliases.difference(call.data["alias"]),
|
||||
)
|
||||
@@ -0,0 +1,40 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import config_validation as cv, floor_registry as fr
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant service to remove an alias from a floor."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "remove_alias_from_floor"
|
||||
schema = {
|
||||
vol.Required("floor_id"): cv.string,
|
||||
vol.Required("alias"): vol.All(cv.ensure_list, [cv.string]),
|
||||
}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
floor_registry = fr.async_get(self.hass)
|
||||
if not (floor := floor_registry.async_get_floor(call.data["floor_id"])):
|
||||
msg = f"Floor {call.data['floor_id']} not found"
|
||||
raise HomeAssistantError(msg)
|
||||
|
||||
aliases = floor.aliases.copy()
|
||||
floor_registry.async_update(
|
||||
call.data["floor_id"],
|
||||
aliases=aliases.difference(call.data["alias"]),
|
||||
)
|
||||
@@ -0,0 +1,34 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.helpers import area_registry as ar, config_validation as cv
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant service to remove an area from a floor."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "remove_area_from_floor"
|
||||
schema = {
|
||||
vol.Required("area_id"): vol.All(cv.ensure_list, [cv.string]),
|
||||
}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
area_registry = ar.async_get(self.hass)
|
||||
for area_id in call.data["area_id"]:
|
||||
area_registry.async_update(
|
||||
area_id,
|
||||
floor_id=None,
|
||||
)
|
||||
@@ -0,0 +1,34 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.helpers import config_validation as cv, device_registry as dr
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant service to remove a device from an area."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "remove_device_from_area"
|
||||
schema = {
|
||||
vol.Required("device_id"): vol.All(cv.ensure_list, [cv.string]),
|
||||
}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
device_registry = dr.async_get(self.hass)
|
||||
for device_id in call.data["device_id"]:
|
||||
device_registry.async_update_device(
|
||||
device_id,
|
||||
area_id=None,
|
||||
)
|
||||
@@ -0,0 +1,34 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant service to remove an entity from an area."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "remove_entity_from_area"
|
||||
schema = {
|
||||
vol.Required("entity_id"): vol.All(cv.ensure_list, [cv.string]),
|
||||
}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
entity_registry = er.async_get(self.hass)
|
||||
for entity_id in call.data["entity_id"]:
|
||||
entity_registry.async_update_entity(
|
||||
entity_id,
|
||||
area_id=None,
|
||||
)
|
||||
@@ -0,0 +1,35 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.helpers import area_registry as ar, config_validation as cv
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant service to remove a label from an area."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "remove_label_from_area"
|
||||
schema = {
|
||||
vol.Required("label_id"): vol.All(cv.ensure_list, [cv.string]),
|
||||
vol.Required("area_id"): vol.All(cv.ensure_list, [cv.string]),
|
||||
}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
area_registry = ar.async_get(self.hass)
|
||||
for area_id in call.data["area_id"]:
|
||||
if area_entry := area_registry.async_get_area(area_id):
|
||||
labels = area_entry.labels.copy()
|
||||
labels.difference_update(call.data["label_id"])
|
||||
area_registry.async_update(area_id, labels=labels)
|
||||
@@ -0,0 +1,35 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.helpers import config_validation as cv, device_registry as dr
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant service to remove a label from a device."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "remove_label_from_device"
|
||||
schema = {
|
||||
vol.Required("label_id"): vol.All(cv.ensure_list, [cv.string]),
|
||||
vol.Required("device_id"): vol.All(cv.ensure_list, [cv.string]),
|
||||
}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
device_registry = dr.async_get(self.hass)
|
||||
for device_id in call.data["device_id"]:
|
||||
if device_entry := device_registry.async_get(device_id):
|
||||
labels = device_entry.labels.copy()
|
||||
labels.difference_update(call.data["label_id"])
|
||||
device_registry.async_update_device(device_id, labels=labels)
|
||||
@@ -0,0 +1,35 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant service to remove a label from an entity."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "remove_label_from_entity"
|
||||
schema = {
|
||||
vol.Required("label_id"): vol.All(cv.ensure_list, [cv.string]),
|
||||
vol.Required("entity_id"): vol.All(cv.ensure_list, [cv.string]),
|
||||
}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
entity_registry = er.async_get(self.hass)
|
||||
for entity_id in call.data["entity_id"]:
|
||||
if entity_entry := entity_registry.async_get(entity_id):
|
||||
labels = entity_entry.labels.copy()
|
||||
labels.difference_update(call.data["label_id"])
|
||||
entity_registry.async_update_entity(entity_id, labels=labels)
|
||||
@@ -0,0 +1,35 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant Core integration service to rename an entity."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "rename_entity"
|
||||
schema = {
|
||||
vol.Required("name"): cv.string,
|
||||
vol.Required("entity_id"): vol.All(cv.ensure_list, [cv.string]),
|
||||
}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
entity_registry = er.async_get(self.hass)
|
||||
for entity_id in call.data["entity_id"]:
|
||||
entity_registry.async_update_entity(
|
||||
entity_id=entity_id,
|
||||
name=call.data["name"],
|
||||
)
|
||||
@@ -0,0 +1,50 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.const import RESTART_EXIT_CODE
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
|
||||
from ....const import LOGGER
|
||||
from ....services import AbstractSpookAdminService, ReplaceExistingService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService, ReplaceExistingService):
|
||||
"""Home Assistant service to restart Home Assistant.
|
||||
|
||||
It overrides the built-in restart service to add a force option.
|
||||
"""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "restart"
|
||||
schema = {
|
||||
vol.Optional("safe_mode", default=False): cv.boolean,
|
||||
vol.Optional("force", default=False): cv.boolean,
|
||||
}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
if call.data["force"]:
|
||||
LOGGER.warning("!! Forcing an Home Assistant restart !!")
|
||||
self.hass.data["homeassistant_stop"] = asyncio.create_task(
|
||||
self.hass.async_stop(RESTART_EXIT_CODE),
|
||||
)
|
||||
return
|
||||
|
||||
if not self.overriden_service:
|
||||
msg = "Spook encountered an error while restarting Home Assistant."
|
||||
raise HomeAssistantError(
|
||||
msg,
|
||||
)
|
||||
|
||||
self.hass.async_run_hass_job(self.overriden_service.job, call)
|
||||
@@ -0,0 +1,39 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import area_registry as ar, config_validation as cv
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant service to set the aliases of an area."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "set_area_aliases"
|
||||
schema = {
|
||||
vol.Required("area_id"): cv.string,
|
||||
vol.Required("aliases"): vol.All(cv.ensure_list, [cv.string]),
|
||||
}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
area_registry = ar.async_get(self.hass)
|
||||
if not area_registry.async_get_area(call.data["area_id"]):
|
||||
msg = f"Area {call.data['area_id']} not found"
|
||||
raise HomeAssistantError(msg)
|
||||
|
||||
area_registry.async_update(
|
||||
call.data["area_id"],
|
||||
aliases=set(call.data["aliases"]),
|
||||
)
|
||||
@@ -0,0 +1,39 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import config_validation as cv, floor_registry as fr
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant service to set the aliases of a floor."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "set_floor_aliases"
|
||||
schema = {
|
||||
vol.Required("floor_id"): cv.string,
|
||||
vol.Required("aliases"): vol.All(cv.ensure_list, [cv.string]),
|
||||
}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
floor_registry = fr.async_get(self.hass)
|
||||
if not floor_registry.async_get_floor(call.data["floor_id"]):
|
||||
msg = f"Floor {call.data['floor_id']} not found"
|
||||
raise HomeAssistantError(msg)
|
||||
|
||||
floor_registry.async_update(
|
||||
call.data["floor_id"],
|
||||
aliases=set(call.data["aliases"]),
|
||||
)
|
||||
@@ -0,0 +1,32 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant Core integration service to unhide an entity."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "unhide_entity"
|
||||
schema = {vol.Required("entity_id"): vol.All(cv.ensure_list, [cv.string])}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
entity_registry = er.async_get(self.hass)
|
||||
for entity_id in call.data["entity_id"]:
|
||||
entity_registry.async_update_entity(
|
||||
entity_id=entity_id,
|
||||
hidden_by=None,
|
||||
)
|
||||
@@ -0,0 +1,34 @@
|
||||
"""Spook - Your homie."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.homeassistant import DOMAIN
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
|
||||
from ....services import AbstractSpookAdminService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.core import ServiceCall
|
||||
|
||||
|
||||
class SpookService(AbstractSpookAdminService):
|
||||
"""Home Assistant Core integration service to update an entity's ID."""
|
||||
|
||||
domain = DOMAIN
|
||||
service = "update_entity_id"
|
||||
schema = {
|
||||
vol.Required("entity_id"): cv.entity_id,
|
||||
vol.Required("new_entity_id"): cv.entity_id,
|
||||
}
|
||||
|
||||
async def async_handle_service(self, call: ServiceCall) -> None:
|
||||
"""Handle the service call."""
|
||||
entity_registry = er.async_get(self.hass)
|
||||
entity_registry.async_update_entity(
|
||||
entity_id=call.data["entity_id"],
|
||||
new_entity_id=call.data["new_entity_id"],
|
||||
)
|
||||
Reference in New Issue
Block a user