mirror of
https://github.com/home-assistant/core.git
synced 2025-07-16 17:57:11 +00:00
Add tplink diagnostics (#65822)
This commit is contained in:
parent
4cd00a1a6f
commit
fd7e2e76e7
46
homeassistant/components/tplink/diagnostics.py
Normal file
46
homeassistant/components/tplink/diagnostics.py
Normal file
@ -0,0 +1,46 @@
|
||||
"""Diagnostics support for TPLink."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.components.diagnostics import async_redact_data
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .const import DOMAIN
|
||||
from .coordinator import TPLinkDataUpdateCoordinator
|
||||
|
||||
TO_REDACT = {
|
||||
# Entry fields
|
||||
"unique_id", # based on mac address
|
||||
# Device identifiers
|
||||
"alias",
|
||||
"mac",
|
||||
"mic_mac",
|
||||
"host",
|
||||
"hwId",
|
||||
"oemId",
|
||||
"deviceId",
|
||||
# Device location
|
||||
"latitude",
|
||||
"latitude_i",
|
||||
"longitude",
|
||||
"longitude_i",
|
||||
# Cloud connectivity info
|
||||
"username",
|
||||
}
|
||||
|
||||
|
||||
async def async_get_config_entry_diagnostics(
|
||||
hass: HomeAssistant, entry: ConfigEntry
|
||||
) -> dict[str, Any]:
|
||||
"""Return diagnostics for a config entry."""
|
||||
coordinator: TPLinkDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
|
||||
device = coordinator.device
|
||||
|
||||
data = {}
|
||||
data[
|
||||
"device_last_response"
|
||||
] = device._last_update # pylint: disable=protected-access
|
||||
|
||||
return async_redact_data(data, TO_REDACT)
|
@ -2,10 +2,16 @@
|
||||
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
from kasa import SmartBulb, SmartDimmer, SmartPlug, SmartStrip
|
||||
from kasa import SmartBulb, SmartDevice, SmartDimmer, SmartPlug, SmartStrip
|
||||
from kasa.exceptions import SmartDeviceException
|
||||
from kasa.protocol import TPLinkSmartHomeProtocol
|
||||
|
||||
from homeassistant.components.tplink import CONF_HOST
|
||||
from homeassistant.components.tplink.const import DOMAIN
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
MODULE = "homeassistant.components.tplink"
|
||||
MODULE_CONFIG_FLOW = "homeassistant.components.tplink.config_flow"
|
||||
IP_ADDRESS = "127.0.0.1"
|
||||
@ -146,3 +152,23 @@ def _patch_single_discovery(device=None, no_device=False):
|
||||
return patch(
|
||||
"homeassistant.components.tplink.Discover.discover_single", new=_discover_single
|
||||
)
|
||||
|
||||
|
||||
async def initialize_config_entry_for_device(
|
||||
hass: HomeAssistant, dev: SmartDevice
|
||||
) -> MockConfigEntry:
|
||||
"""Create a mocked configuration entry for the given device.
|
||||
|
||||
Note, the rest of the tests should probably be converted over to use this
|
||||
instead of repeating the initialization routine for each test separately
|
||||
"""
|
||||
config_entry = MockConfigEntry(
|
||||
title="TP-Link", domain=DOMAIN, unique_id=dev.mac, data={CONF_HOST: dev.host}
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
with _patch_discovery(device=dev), _patch_single_discovery(device=dev):
|
||||
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
return config_entry
|
||||
|
@ -1,116 +0,0 @@
|
||||
"""Constants for the TP-Link component tests."""
|
||||
|
||||
SMARTPLUG_HS110_DATA = {
|
||||
"sysinfo": {
|
||||
"sw_ver": "1.0.4 Build 191111 Rel.143500",
|
||||
"hw_ver": "4.0",
|
||||
"model": "HS110(EU)",
|
||||
"deviceId": "4C56447B395BB7A2FAC68C9DFEE2E84163222581",
|
||||
"oemId": "40F54B43071E9436B6395611E9D91CEA",
|
||||
"hwId": "A6C77E4FDD238B53D824AC8DA361F043",
|
||||
"rssi": -24,
|
||||
"longitude_i": 130793,
|
||||
"latitude_i": 480582,
|
||||
"alias": "SmartPlug",
|
||||
"status": "new",
|
||||
"mic_type": "IOT.SMARTPLUGSWITCH",
|
||||
"feature": "TIM:ENE",
|
||||
"mac": "69:F2:3C:8E:E3:47",
|
||||
"updating": 0,
|
||||
"led_off": 0,
|
||||
"relay_state": 0,
|
||||
"on_time": 0,
|
||||
"active_mode": "none",
|
||||
"icon_hash": "",
|
||||
"dev_name": "Smart Wi-Fi Plug With Energy Monitoring",
|
||||
"next_action": {"type": -1},
|
||||
"err_code": 0,
|
||||
},
|
||||
"realtime": {
|
||||
"voltage_mv": 233957,
|
||||
"current_ma": 21,
|
||||
"power_mw": 0,
|
||||
"total_wh": 1793,
|
||||
"err_code": 0,
|
||||
},
|
||||
}
|
||||
SMARTPLUG_HS100_DATA = {
|
||||
"sysinfo": {
|
||||
"sw_ver": "1.0.4 Build 191111 Rel.143500",
|
||||
"hw_ver": "4.0",
|
||||
"model": "HS100(EU)",
|
||||
"deviceId": "4C56447B395BB7A2FAC68C9DFEE2E84163222581",
|
||||
"oemId": "40F54B43071E9436B6395611E9D91CEA",
|
||||
"hwId": "A6C77E4FDD238B53D824AC8DA361F043",
|
||||
"rssi": -24,
|
||||
"longitude_i": 130793,
|
||||
"latitude_i": 480582,
|
||||
"alias": "SmartPlug",
|
||||
"status": "new",
|
||||
"mic_type": "IOT.SMARTPLUGSWITCH",
|
||||
"feature": "TIM:",
|
||||
"mac": "A9:F4:3D:A4:E3:47",
|
||||
"updating": 0,
|
||||
"led_off": 0,
|
||||
"relay_state": 0,
|
||||
"on_time": 0,
|
||||
"active_mode": "none",
|
||||
"icon_hash": "",
|
||||
"dev_name": "Smart Wi-Fi Plug",
|
||||
"next_action": {"type": -1},
|
||||
"err_code": 0,
|
||||
}
|
||||
}
|
||||
SMARTSTRIP_KP303_DATA = {
|
||||
"sysinfo": {
|
||||
"sw_ver": "1.0.4 Build 210428 Rel.135415",
|
||||
"hw_ver": "1.0",
|
||||
"model": "KP303(AU)",
|
||||
"deviceId": "03102547AB1A57A4E4AA5B4EFE34C3005726B97D",
|
||||
"oemId": "1F950FC9BFF278D9D35E046C129D9411",
|
||||
"hwId": "9E86D4F840D2787D3D7A6523A731BA2C",
|
||||
"rssi": -74,
|
||||
"longitude_i": 1158985,
|
||||
"latitude_i": -319172,
|
||||
"alias": "TP-LINK_Power Strip_00B1",
|
||||
"status": "new",
|
||||
"mic_type": "IOT.SMARTPLUGSWITCH",
|
||||
"feature": "TIM",
|
||||
"mac": "D4:DD:D6:95:B0:F9",
|
||||
"updating": 0,
|
||||
"led_off": 0,
|
||||
"children": [
|
||||
{
|
||||
"id": "8006B399B7FE68D4E6991CCCEA239C081DFA913000",
|
||||
"state": 0,
|
||||
"alias": "R-Plug 1",
|
||||
"on_time": 0,
|
||||
"next_action": {"type": -1},
|
||||
},
|
||||
{
|
||||
"id": "8006B399B7FE68D4E6991CCCEA239C081DFA913001",
|
||||
"state": 1,
|
||||
"alias": "R-Plug 2",
|
||||
"on_time": 93835,
|
||||
"next_action": {"type": -1},
|
||||
},
|
||||
{
|
||||
"id": "8006B399B7FE68D4E6991CCCEA239C081DFA913002",
|
||||
"state": 1,
|
||||
"alias": "R-Plug 3",
|
||||
"on_time": 93834,
|
||||
"next_action": {"type": -1},
|
||||
},
|
||||
],
|
||||
"child_num": 3,
|
||||
"err_code": 0,
|
||||
},
|
||||
"realtime": {
|
||||
"voltage_mv": 233957,
|
||||
"current_ma": 21,
|
||||
"power_mw": 0,
|
||||
"total_wh": 1793,
|
||||
"err_code": 0,
|
||||
},
|
||||
"context": "1",
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
{
|
||||
"device_last_response": {
|
||||
"system": {
|
||||
"get_sysinfo": {
|
||||
"sw_ver": "1.8.8 Build 190613 Rel.123436",
|
||||
"hw_ver": "1.0",
|
||||
"model": "KL130(EU)",
|
||||
"description": "Smart Wi-Fi LED Bulb with Color Changing",
|
||||
"alias": "bedroom light",
|
||||
"mic_type": "IOT.SMARTBULB",
|
||||
"dev_state": "normal",
|
||||
"mic_mac": "aa:bb:cc:dd:ee:ff",
|
||||
"deviceId": "1234",
|
||||
"oemId": "1234",
|
||||
"hwId": "1234",
|
||||
"is_factory": false,
|
||||
"disco_ver": "1.0",
|
||||
"ctrl_protocols": {
|
||||
"name": "Linkie",
|
||||
"version": "1.0"
|
||||
},
|
||||
"light_state": {
|
||||
"on_off": 1,
|
||||
"mode": "normal",
|
||||
"hue": 0,
|
||||
"saturation": 0,
|
||||
"color_temp": 2500,
|
||||
"brightness": 58
|
||||
},
|
||||
"is_dimmable": 1,
|
||||
"is_color": 1,
|
||||
"is_variable_color_temp": 1,
|
||||
"preferred_state": [
|
||||
{
|
||||
"index": 0,
|
||||
"hue": 0,
|
||||
"saturation": 0,
|
||||
"color_temp": 2500,
|
||||
"brightness": 10
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"hue": 299,
|
||||
"saturation": 95,
|
||||
"color_temp": 0,
|
||||
"brightness": 100
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"hue": 120,
|
||||
"saturation": 75,
|
||||
"color_temp": 0,
|
||||
"brightness": 100
|
||||
},
|
||||
{
|
||||
"index": 3,
|
||||
"hue": 240,
|
||||
"saturation": 75,
|
||||
"color_temp": 0,
|
||||
"brightness": 100
|
||||
}
|
||||
],
|
||||
"rssi": -66,
|
||||
"active_mode": "none",
|
||||
"heapsize": 334532,
|
||||
"err_code": 0
|
||||
}
|
||||
},
|
||||
"smartlife.iot.common.emeter": {
|
||||
"get_realtime": {
|
||||
"power_mw": 6600,
|
||||
"err_code": 0
|
||||
},
|
||||
"get_monthstat": {
|
||||
"month_list": [
|
||||
{
|
||||
"year": 2022,
|
||||
"month": 1,
|
||||
"energy_wh": 321
|
||||
},
|
||||
{
|
||||
"year": 2022,
|
||||
"month": 2,
|
||||
"energy_wh": 321
|
||||
}
|
||||
],
|
||||
"err_code": 0
|
||||
},
|
||||
"get_daystat": {
|
||||
"day_list": [
|
||||
{
|
||||
"year": 2022,
|
||||
"month": 2,
|
||||
"day": 1,
|
||||
"energy_wh": 123
|
||||
},
|
||||
{
|
||||
"year": 2022,
|
||||
"month": 2,
|
||||
"day": 2,
|
||||
"energy_wh": 123
|
||||
}
|
||||
],
|
||||
"err_code": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
{
|
||||
"device_last_response": {
|
||||
"system": {
|
||||
"get_sysinfo": {
|
||||
"sw_ver": "1.0.4 Build 191111 Rel.143500",
|
||||
"hw_ver": "4.0",
|
||||
"model": "HS110(EU)",
|
||||
"deviceId": "1234",
|
||||
"oemId": "1234",
|
||||
"hwId": "1234",
|
||||
"rssi": -57,
|
||||
"longitude_i": "0.0",
|
||||
"latitude_i": "0.0",
|
||||
"alias": "some plug",
|
||||
"status": "new",
|
||||
"mic_type": "IOT.SMARTPLUGSWITCH",
|
||||
"feature": "TIM:ENE",
|
||||
"mac": "aa:bb:cc:dd:ee:ff",
|
||||
"updating": 0,
|
||||
"led_off": 1,
|
||||
"relay_state": 1,
|
||||
"on_time": 254454,
|
||||
"active_mode": "none",
|
||||
"icon_hash": "",
|
||||
"dev_name": "Smart Wi-Fi Plug With Energy Monitoring",
|
||||
"next_action": {
|
||||
"type": -1
|
||||
},
|
||||
"err_code": 0
|
||||
}
|
||||
},
|
||||
"emeter": {
|
||||
"get_realtime": {
|
||||
"voltage_mv": 230118,
|
||||
"current_ma": 303,
|
||||
"power_mw": 28825,
|
||||
"total_wh": 18313,
|
||||
"err_code": 0
|
||||
},
|
||||
"get_monthstat": {
|
||||
"month_list": [
|
||||
{
|
||||
"year": 2022,
|
||||
"month": 2,
|
||||
"energy_wh": 321
|
||||
},
|
||||
{
|
||||
"year": 2022,
|
||||
"month": 1,
|
||||
"energy_wh": 321
|
||||
}
|
||||
],
|
||||
"err_code": 0
|
||||
},
|
||||
"get_daystat": {
|
||||
"day_list": [
|
||||
{
|
||||
"year": 2022,
|
||||
"month": 2,
|
||||
"day": 1,
|
||||
"energy_wh": 123
|
||||
},
|
||||
{
|
||||
"year": 2022,
|
||||
"month": 2,
|
||||
"day": 2,
|
||||
"energy_wh": 123
|
||||
}
|
||||
],
|
||||
"err_code": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
60
tests/components/tplink/test_diagnostics.py
Normal file
60
tests/components/tplink/test_diagnostics.py
Normal file
@ -0,0 +1,60 @@
|
||||
"""Tests for the diagnostics data provided by the TP-Link integration."""
|
||||
import json
|
||||
|
||||
from aiohttp import ClientSession
|
||||
from kasa import SmartDevice
|
||||
import pytest
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from . import _mocked_bulb, _mocked_plug, initialize_config_entry_for_device
|
||||
|
||||
from tests.common import load_fixture
|
||||
from tests.components.diagnostics import get_diagnostics_for_config_entry
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mocked_dev,fixture_file,sysinfo_vars",
|
||||
[
|
||||
(
|
||||
_mocked_bulb(),
|
||||
"tplink-diagnostics-data-bulb-kl130.json",
|
||||
["mic_mac", "deviceId", "oemId", "hwId", "alias"],
|
||||
),
|
||||
(
|
||||
_mocked_plug(),
|
||||
"tplink-diagnostics-data-plug-hs110.json",
|
||||
["mac", "deviceId", "oemId", "hwId", "alias", "longitude_i", "latitude_i"],
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_diagnostics(
|
||||
hass: HomeAssistant,
|
||||
hass_client: ClientSession,
|
||||
mocked_dev: SmartDevice,
|
||||
fixture_file: str,
|
||||
sysinfo_vars: list[str],
|
||||
):
|
||||
"""Test diagnostics for config entry."""
|
||||
diagnostics_data = json.loads(load_fixture(fixture_file, "tplink"))
|
||||
|
||||
mocked_dev._last_update = diagnostics_data["device_last_response"]
|
||||
|
||||
config_entry = await initialize_config_entry_for_device(hass, mocked_dev)
|
||||
result = await get_diagnostics_for_config_entry(hass, hass_client, config_entry)
|
||||
|
||||
assert isinstance(result, dict)
|
||||
assert "device_last_response" in result
|
||||
|
||||
# There must be some redactions in place, so the raw data must not match
|
||||
assert result["device_last_response"] != diagnostics_data["device_last_response"]
|
||||
|
||||
last_response = result["device_last_response"]
|
||||
|
||||
# We should always have sysinfo available
|
||||
assert "system" in last_response
|
||||
assert "get_sysinfo" in last_response["system"]
|
||||
|
||||
sysinfo = last_response["system"]["get_sysinfo"]
|
||||
for var in sysinfo_vars:
|
||||
assert sysinfo[var] == "**REDACTED**"
|
Loading…
x
Reference in New Issue
Block a user