Comments (3)
Use the Studio Code Server add-on in Home Assistant and open file:
custom_components -> tplink_deco -> init.py
And replace the complete code with this:
"""
Custom integration to integrate TP-Link Deco with Home Assistant.
For more details about this integration, please refer to
https://github.com/amosyuen/ha-tplink-deco
"""
import asyncio
import logging
from datetime import timedelta
from typing import Any
from typing import cast
import homeassistant.helpers.config_validation as cv
import voluptuous as vol
from homeassistant.components.device_tracker.const import CONF_CONSIDER_HOME
from homeassistant.components.device_tracker.const import CONF_SCAN_INTERVAL
from homeassistant.components.device_tracker.const import (
DOMAIN as DEVICE_TRACKER_DOMAIN,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_DEVICE_ID
from homeassistant.const import CONF_HOST
from homeassistant.const import CONF_PASSWORD
from homeassistant.const import CONF_USERNAME
from homeassistant.core import Config
from homeassistant.core import HomeAssistant
from homeassistant.core import ServiceCall
from homeassistant.helpers import device_registry
from homeassistant.helpers import entity_registry
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.restore_state import RestoreEntity
from .api import TplinkDecoApi
from .const import ATTR_DEVICE_TYPE
from .const import CONF_TIMEOUT_ERROR_RETRIES
from .const import CONF_TIMEOUT_SECONDS
from .const import CONF_VERIFY_SSL
from .const import COORDINATOR_CLIENTS_KEY
from .const import COORDINATOR_DECOS_KEY
from .const import DEFAULT_CONSIDER_HOME
from .const import DEFAULT_SCAN_INTERVAL
from .const import DEFAULT_TIMEOUT_ERROR_RETRIES
from .const import DEFAULT_TIMEOUT_SECONDS
from .const import DEVICE_TYPE_DECO
from .const import DOMAIN
from .const import PLATFORMS
from .const import SERVICE_REBOOT_DECO
from .coordinator import TpLinkDeco
from .coordinator import TpLinkDecoClient
from .coordinator import TplinkDecoClientUpdateCoordinator
from .coordinator import TpLinkDecoData
from .coordinator import TplinkDecoUpdateCoordinator
_LOGGER: logging.Logger = logging.getLogger(__name__)
async def async_create_and_refresh_coordinators(
hass: HomeAssistant,
config_data: dict[str:Any],
consider_home_seconds,
update_interval: timedelta = None,
deco_data: TpLinkDecoData = None,
client_data: dict[str:TpLinkDecoClient] = None,
):
host = config_data.get(CONF_HOST)
username = config_data.get(CONF_USERNAME)
password = config_data.get(CONF_PASSWORD)
timeout_error_retries = config_data.get(CONF_TIMEOUT_ERROR_RETRIES)
timeout_seconds = config_data.get(CONF_TIMEOUT_SECONDS)
verify_ssl = config_data.get(CONF_VERIFY_SSL)
session = async_get_clientsession(hass)
api = TplinkDecoApi(
session,
host,
username,
password,
verify_ssl,
timeout_error_retries,
timeout_seconds,
)
deco_coordinator = TplinkDecoUpdateCoordinator(
hass, api, update_interval, deco_data
)
await deco_coordinator.async_config_entry_first_refresh()
clients_coordinator = TplinkDecoClientUpdateCoordinator(
hass,
api,
deco_coordinator,
consider_home_seconds,
update_interval,
client_data,
)
await clients_coordinator.async_config_entry_first_refresh()
return {
COORDINATOR_DECOS_KEY: deco_coordinator,
COORDINATOR_CLIENTS_KEY: clients_coordinator,
}
async def async_create_config_data(hass: HomeAssistant, config_entry: ConfigEntry):
consider_home_seconds = config_entry.data.get(
CONF_CONSIDER_HOME, DEFAULT_CONSIDER_HOME
)
scan_interval_seconds = config_entry.data.get(
CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL
)
update_interval = timedelta(seconds=scan_interval_seconds)
# Load tracked entities from registry
existing_entries = entity_registry.async_entries_for_config_entry(
entity_registry.async_get(hass),
config_entry.entry_id,
)
deco_data = TpLinkDecoData()
client_data = {}
last_states = hass.states.async_all()
for entry in existing_entries:
if entry.domain != DEVICE_TRACKER_DOMAIN:
continue
state = hass.states.get(entry.entity_id)
if state is None:
continue
device_type = state.attributes.get(ATTR_DEVICE_TYPE)
if device_type is None:
continue
if device_type == DEVICE_TYPE_DECO:
deco = TpLinkDeco(entry.unique_id)
deco.name = entry.original_name
deco_data.decos[entry.unique_id] = deco
else:
client = TpLinkDecoClient(entry.unique_id)
client.name = entry.original_name
client_data[entry.unique_id] = client
return await async_create_and_refresh_coordinators(
hass,
config_entry.data,
consider_home_seconds,
update_interval,
deco_data,
client_data,
)
async def async_setup(hass: HomeAssistant, config: Config):
"""Set up this integration using YAML is not supported."""
return True
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry):
"""Set up this integration using UI."""
if hass.data.get(DOMAIN) is None:
hass.data.setdefault(DOMAIN, {})
data = await async_create_config_data(hass, config_entry)
hass.data[DOMAIN][config_entry.entry_id] = data
deco_coordinator = data[COORDINATOR_DECOS_KEY]
for platform in PLATFORMS:
hass.async_add_job(
hass.config_entries.async_forward_entry_setup(config_entry, platform)
)
async def async_reboot_deco(service: ServiceCall) -> None:
dr = device_registry.async_get(hass=hass)
device_ids = cast([str], service.data.get(ATTR_DEVICE_ID))
macs = []
for device_id in device_ids:
device = dr.async_get(device_id)
if device is None:
raise Exception(f"Device ID {device_id} is not a TP-Link Deco device")
ids = device.identifiers
id = next(iter(ids)) if len(ids) == 1 else None
if id[0] != DOMAIN:
raise Exception(
f"Device ID {device_id} does not have {DOMAIN} MAC identifier"
)
macs.append(id[1])
await deco_coordinator.api.async_reboot_decos(macs)
hass.services.async_register(
DOMAIN,
SERVICE_REBOOT_DECO,
async_reboot_deco,
schema=vol.Schema(
{
vol.Required(ATTR_DEVICE_ID): vol.All(cv.ensure_list(str), [str]),
}
),
)
config_entry.async_on_unload(config_entry.add_update_listener(update_listener))
return True
async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
"""Handle removal of an entry."""
data = hass.data[DOMAIN][config_entry.entry_id]
deco_coordinator = data.get(COORDINATOR_DECOS_KEY)
clients_coordinator = data.get(COORDINATOR_CLIENTS_KEY)
if deco_coordinator is not None:
await deco_coordinator.async_stop()
if clients_coordinator is not None:
await clients_coordinator.async_stop()
unload_ok = await hass.config_entries.async_unload_platforms(config_entry, PLATFORMS)
if unload_ok:
hass.data[DOMAIN].pop(config_entry.entry_id)
return unload_ok
async def update_listener(hass: HomeAssistant, config_entry: ConfigEntry) -> None:
"""Handle options update."""
data = hass.data[DOMAIN][config_entry.entry_id]
deco_coordinator = data[COORDINATOR_DECOS_KEY]
clients_coordinator = data[COORDINATOR_CLIENTS_KEY]
await deco_coordinator.api.async_update_options(config_entry.data)
deco_coordinator.update_interval = timedelta(
seconds=config_entry.data.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL)
)
await deco_coordinator.async_config_entry_first_refresh()
await clients_coordinator.async_config_entry_first_refresh()
class TpLinkDecoDevice(RestoreEntity):
"""Representation of a TP-Link Deco device."""
def __init__(
self,
config_entry: ConfigEntry,
coordinator: TplinkDecoUpdateCoordinator,
deco_id: str,
):
"""Initialize the TP-Link Deco device."""
self.config_entry = config_entry
self.coordinator = coordinator
self.deco_id = deco_id
self.deco: TpLinkDeco | None = None
@property
def unique_id(self) -> str:
"""Return a unique ID for the device."""
return f"{DOMAIN}-{self.deco_id}"
@property
def name(self) -> str:
"""Return the name of the device."""
if self.deco is not None:
return self.deco.name
return ""
@property
def available(self) -> bool:
"""Return True if the device is available."""
return self.coordinator.last_update_success and self.deco_id in self.coordinator.data.decos
async def async_added_to_hass(self):
"""Subscribe to updates."""
self.async_on_remove(
self.coordinator.async_add_listener(self.async_write_ha_state)
)
await super().async_added_to_hass()
async def async_update(self):
"""Update the device."""
self.deco = self.coordinator.data.decos.get(self.deco_id)
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn on the device."""
await self.coordinator.api.async_turn_on_deco(self.deco_id)
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn off the device."""
await self.coordinator.api.async_turn_off_deco(self.deco_id)
class TpLinkDecoClientDevice(RestoreEntity):
"""Representation of a TP-Link Deco client device."""
def __init__(
self,
config_entry: ConfigEntry,
coordinator: TplinkDecoClientUpdateCoordinator,
client_id: str,
):
"""Initialize the TP-Link Deco client device."""
self.config_entry = config_entry
self.coordinator = coordinator
self.client_id = client_id
self.client: TpLinkDecoClient | None = None
@property
def unique_id(self) -> str:
"""Return a unique ID for the device."""
return f"{DOMAIN}-{self.client_id}"
@property
def name(self) -> str:
"""Return the name of the device."""
if self.client is not None:
return self.client.name
return ""
@property
def available(self) -> bool:
"""Return True if the device is available."""
return (
self.coordinator.last_update_success
and self.client_id in self.coordinator.data.clients
)
@property
def device_info(self) -> dict[str, Any]:
"""Return the device info."""
device_id = self.client_id.split(":")[0]
device = device_registry.async_get(hass=self.hass).async_get(device_id)
if device is not None:
return {
"identifiers": {(DOMAIN, device_id)},
"name": device.name,
"manufacturer": "TP-Link",
"model": device.model,
}
return {}
@property
def device_state_attributes(self) -> dict[str, Any]:
"""Return the state attributes of the device."""
if self.client is not None:
return {
ATTR_DEVICE_TYPE: self.client.device_type,
}
return {}
async def async_added_to_hass(self):
"""Subscribe to updates."""
self.async_on_remove(
self.coordinator.async_add_listener(self.async_write_ha_state)
)
await super().async_added_to_hass()
async def async_update(self):
"""Update the device."""
self.client = self.coordinator.data.clients.get(self.client_id)
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn on the device."""
await self.coordinator.api.async_turn_on_client(self.client_id)
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn off the device."""
await self.coordinator.api.async_turn_off_client(self.client_id)
async def async_migrate_entry(hass, config_entry):
"""Migrate old entry."""
_LOGGER.debug("Migrating TP-Link Deco entry from version %s", config_entry.version)
data = config_entry.data
options = config_entry.options
version = config_entry.version
if version == 1:
data[CONF_VERIFY_SSL] = True
options[CONF_SCAN_INTERVAL] = options.pop(CONF_UPDATE_INTERVAL, 5 * 60)
config_entry.version = 2
hass.config_entries.async_update_entry(config_entry, data=data, options=options)
_LOGGER.info("Migration to version %s successful", config_entry.version)
return True
This fixed it for me.
from ha-tplink-deco.
Sorry it didn't... It's not working unfortunatly...
from ha-tplink-deco.
Duplicate #187
from ha-tplink-deco.
Related Issues (20)
- M9 Plus and http -> https update HOT 4
- 타임아웃 발생 시 json에 다른 속성으로 응답이 올때가 있습니다. HOT 1
- Feature request: Total used data HOT 1
- device_tracker entities suddenly Unavailable HOT 3
- Integration stopped working with Deco X20 after firmware upgrade HOT 2
- Error setting up HOT 2
- Clearing of Old Client Devices after Inactive Timeout Period HOT 1
- Error Connecting to x20version2 units HOT 3
- SOURCE_TYPE_ROUTER deprecated HOT 1
- Is there anyway to detect that Guest Wifi is turning on or off? HOT 1
- The client prefix is added multiple times
- TP-Link Deco Not reporting to HA that a device is on the network
- Deprecation Warning in HA 2024.4+ HOT 6
- Add KS240 integration HOT 1
- Configuration - Client name prefix and postfix seem to be ignored
- 'tplink_deco' calls `async_add_job`, which is deprecated and will be removed HOT 2
- async_add_job will be deprecated HOT 1
- Can’t install the intégration HOT 1
- Unexpected error fetching tplink_deco-clients data HOT 1
- Unable to reach host 502 error
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from ha-tplink-deco.