2019-06-02 05:13:14 +00:00
|
|
|
"""Support for AdGuard Home."""
|
|
|
|
import logging
|
|
|
|
from typing import Any, Dict
|
|
|
|
|
2019-10-19 19:11:09 +00:00
|
|
|
from adguardhome import AdGuardHome, AdGuardHomeConnectionError, AdGuardHomeError
|
2019-06-02 05:13:14 +00:00
|
|
|
import voluptuous as vol
|
|
|
|
|
|
|
|
from homeassistant.components.adguard.const import (
|
2019-07-31 19:25:30 +00:00
|
|
|
CONF_FORCE,
|
|
|
|
DATA_ADGUARD_CLIENT,
|
|
|
|
DATA_ADGUARD_VERION,
|
|
|
|
DOMAIN,
|
|
|
|
SERVICE_ADD_URL,
|
|
|
|
SERVICE_DISABLE_URL,
|
|
|
|
SERVICE_ENABLE_URL,
|
|
|
|
SERVICE_REFRESH,
|
|
|
|
SERVICE_REMOVE_URL,
|
|
|
|
)
|
2019-06-02 05:13:14 +00:00
|
|
|
from homeassistant.config_entries import ConfigEntry
|
|
|
|
from homeassistant.const import (
|
2019-07-31 19:25:30 +00:00
|
|
|
CONF_HOST,
|
|
|
|
CONF_NAME,
|
|
|
|
CONF_PASSWORD,
|
|
|
|
CONF_PORT,
|
|
|
|
CONF_SSL,
|
|
|
|
CONF_URL,
|
|
|
|
CONF_USERNAME,
|
|
|
|
CONF_VERIFY_SSL,
|
|
|
|
)
|
2019-10-19 19:11:09 +00:00
|
|
|
from homeassistant.exceptions import ConfigEntryNotReady
|
2019-06-02 05:13:14 +00:00
|
|
|
from homeassistant.helpers import config_validation as cv
|
|
|
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
|
|
|
from homeassistant.helpers.entity import Entity
|
|
|
|
from homeassistant.helpers.typing import ConfigType, HomeAssistantType
|
|
|
|
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
SERVICE_URL_SCHEMA = vol.Schema({vol.Required(CONF_URL): cv.url})
|
|
|
|
SERVICE_ADD_URL_SCHEMA = vol.Schema(
|
|
|
|
{vol.Required(CONF_NAME): cv.string, vol.Required(CONF_URL): cv.url}
|
|
|
|
)
|
|
|
|
SERVICE_REFRESH_SCHEMA = vol.Schema(
|
|
|
|
{vol.Optional(CONF_FORCE, default=False): cv.boolean}
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool:
|
|
|
|
"""Set up the AdGuard Home components."""
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool:
|
2019-06-02 05:13:14 +00:00
|
|
|
"""Set up AdGuard Home from a config entry."""
|
|
|
|
session = async_get_clientsession(hass, entry.data[CONF_VERIFY_SSL])
|
|
|
|
adguard = AdGuardHome(
|
|
|
|
entry.data[CONF_HOST],
|
|
|
|
port=entry.data[CONF_PORT],
|
|
|
|
username=entry.data[CONF_USERNAME],
|
|
|
|
password=entry.data[CONF_PASSWORD],
|
|
|
|
tls=entry.data[CONF_SSL],
|
|
|
|
verify_ssl=entry.data[CONF_VERIFY_SSL],
|
|
|
|
session=session,
|
|
|
|
)
|
|
|
|
|
|
|
|
hass.data.setdefault(DOMAIN, {})[DATA_ADGUARD_CLIENT] = adguard
|
|
|
|
|
2019-10-19 19:11:09 +00:00
|
|
|
try:
|
2020-07-28 15:51:35 +00:00
|
|
|
await adguard.version()
|
2019-10-19 19:11:09 +00:00
|
|
|
except AdGuardHomeConnectionError as exception:
|
|
|
|
raise ConfigEntryNotReady from exception
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
for component in "sensor", "switch":
|
2019-06-02 05:13:14 +00:00
|
|
|
hass.async_create_task(
|
|
|
|
hass.config_entries.async_forward_entry_setup(entry, component)
|
|
|
|
)
|
|
|
|
|
|
|
|
async def add_url(call) -> None:
|
|
|
|
"""Service call to add a new filter subscription to AdGuard Home."""
|
|
|
|
await adguard.filtering.add_url(
|
|
|
|
call.data.get(CONF_NAME), call.data.get(CONF_URL)
|
|
|
|
)
|
|
|
|
|
|
|
|
async def remove_url(call) -> None:
|
|
|
|
"""Service call to remove a filter subscription from AdGuard Home."""
|
|
|
|
await adguard.filtering.remove_url(call.data.get(CONF_URL))
|
|
|
|
|
|
|
|
async def enable_url(call) -> None:
|
|
|
|
"""Service call to enable a filter subscription in AdGuard Home."""
|
|
|
|
await adguard.filtering.enable_url(call.data.get(CONF_URL))
|
|
|
|
|
|
|
|
async def disable_url(call) -> None:
|
|
|
|
"""Service call to disable a filter subscription in AdGuard Home."""
|
|
|
|
await adguard.filtering.disable_url(call.data.get(CONF_URL))
|
|
|
|
|
|
|
|
async def refresh(call) -> None:
|
|
|
|
"""Service call to refresh the filter subscriptions in AdGuard Home."""
|
|
|
|
await adguard.filtering.refresh(call.data.get(CONF_FORCE))
|
|
|
|
|
|
|
|
hass.services.async_register(
|
|
|
|
DOMAIN, SERVICE_ADD_URL, add_url, schema=SERVICE_ADD_URL_SCHEMA
|
|
|
|
)
|
|
|
|
hass.services.async_register(
|
|
|
|
DOMAIN, SERVICE_REMOVE_URL, remove_url, schema=SERVICE_URL_SCHEMA
|
|
|
|
)
|
|
|
|
hass.services.async_register(
|
|
|
|
DOMAIN, SERVICE_ENABLE_URL, enable_url, schema=SERVICE_URL_SCHEMA
|
|
|
|
)
|
|
|
|
hass.services.async_register(
|
|
|
|
DOMAIN, SERVICE_DISABLE_URL, disable_url, schema=SERVICE_URL_SCHEMA
|
|
|
|
)
|
|
|
|
hass.services.async_register(
|
|
|
|
DOMAIN, SERVICE_REFRESH, refresh, schema=SERVICE_REFRESH_SCHEMA
|
|
|
|
)
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
async def async_unload_entry(hass: HomeAssistantType, entry: ConfigType) -> bool:
|
2019-06-02 05:13:14 +00:00
|
|
|
"""Unload AdGuard Home config entry."""
|
|
|
|
hass.services.async_remove(DOMAIN, SERVICE_ADD_URL)
|
|
|
|
hass.services.async_remove(DOMAIN, SERVICE_REMOVE_URL)
|
|
|
|
hass.services.async_remove(DOMAIN, SERVICE_ENABLE_URL)
|
|
|
|
hass.services.async_remove(DOMAIN, SERVICE_DISABLE_URL)
|
|
|
|
hass.services.async_remove(DOMAIN, SERVICE_REFRESH)
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
for component in "sensor", "switch":
|
2019-06-02 05:13:14 +00:00
|
|
|
await hass.config_entries.async_forward_entry_unload(entry, component)
|
|
|
|
|
|
|
|
del hass.data[DOMAIN]
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
class AdGuardHomeEntity(Entity):
|
|
|
|
"""Defines a base AdGuard Home entity."""
|
|
|
|
|
2020-01-23 23:50:59 +00:00
|
|
|
def __init__(
|
|
|
|
self, adguard, name: str, icon: str, enabled_default: bool = True
|
|
|
|
) -> None:
|
2019-06-02 05:13:14 +00:00
|
|
|
"""Initialize the AdGuard Home entity."""
|
|
|
|
self._available = True
|
2020-01-23 23:50:59 +00:00
|
|
|
self._enabled_default = enabled_default
|
|
|
|
self._icon = icon
|
|
|
|
self._name = name
|
2019-06-02 05:13:14 +00:00
|
|
|
self.adguard = adguard
|
|
|
|
|
|
|
|
@property
|
|
|
|
def name(self) -> str:
|
|
|
|
"""Return the name of the entity."""
|
|
|
|
return self._name
|
|
|
|
|
|
|
|
@property
|
|
|
|
def icon(self) -> str:
|
|
|
|
"""Return the mdi icon of the entity."""
|
|
|
|
return self._icon
|
|
|
|
|
2020-01-23 23:50:59 +00:00
|
|
|
@property
|
|
|
|
def entity_registry_enabled_default(self) -> bool:
|
|
|
|
"""Return if the entity should be enabled when first added to the entity registry."""
|
|
|
|
return self._enabled_default
|
|
|
|
|
2019-06-02 05:13:14 +00:00
|
|
|
@property
|
|
|
|
def available(self) -> bool:
|
|
|
|
"""Return True if entity is available."""
|
|
|
|
return self._available
|
|
|
|
|
|
|
|
async def async_update(self) -> None:
|
|
|
|
"""Update AdGuard Home entity."""
|
2020-01-23 23:50:59 +00:00
|
|
|
if not self.enabled:
|
|
|
|
return
|
|
|
|
|
2019-06-02 05:13:14 +00:00
|
|
|
try:
|
|
|
|
await self._adguard_update()
|
|
|
|
self._available = True
|
|
|
|
except AdGuardHomeError:
|
|
|
|
if self._available:
|
|
|
|
_LOGGER.debug(
|
2020-07-05 21:04:19 +00:00
|
|
|
"An error occurred while updating AdGuard Home sensor",
|
2019-06-02 05:13:14 +00:00
|
|
|
exc_info=True,
|
|
|
|
)
|
|
|
|
self._available = False
|
|
|
|
|
|
|
|
async def _adguard_update(self) -> None:
|
|
|
|
"""Update AdGuard Home entity."""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
|
|
|
|
class AdGuardHomeDeviceEntity(AdGuardHomeEntity):
|
|
|
|
"""Defines a AdGuard Home device entity."""
|
|
|
|
|
|
|
|
@property
|
|
|
|
def device_info(self) -> Dict[str, Any]:
|
|
|
|
"""Return device information about this AdGuard Home instance."""
|
|
|
|
return {
|
2019-07-31 19:25:30 +00:00
|
|
|
"identifiers": {
|
|
|
|
(DOMAIN, self.adguard.host, self.adguard.port, self.adguard.base_path)
|
2019-06-02 05:13:14 +00:00
|
|
|
},
|
2019-07-31 19:25:30 +00:00
|
|
|
"name": "AdGuard Home",
|
|
|
|
"manufacturer": "AdGuard Team",
|
|
|
|
"sw_version": self.hass.data[DOMAIN].get(DATA_ADGUARD_VERION),
|
2020-05-05 00:30:21 +00:00
|
|
|
"entry_type": "service",
|
2019-06-02 05:13:14 +00:00
|
|
|
}
|