mirror of
https://github.com/home-assistant/core.git
synced 2026-09-27 18:08:37 -04:00
Move TP-Link power and energy switch attributes to sensors (#53596)
Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
This commit is contained in:
co-authored by
Paulus Schoutsen
parent
24a589961a
commit
bedb9550f5
@@ -0,0 +1,72 @@
|
||||
"""Constants for the TP-Link component tests."""
|
||||
|
||||
SMARTPLUGSWITCH_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,
|
||||
},
|
||||
}
|
||||
SMARTSTRIPWITCH_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",
|
||||
"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},
|
||||
"children": [{"id": "1", "state": 1, "alias": "SmartPlug#1"}],
|
||||
"err_code": 0,
|
||||
},
|
||||
"realtime": {
|
||||
"voltage_mv": 233957,
|
||||
"current_ma": 21,
|
||||
"power_mw": 0,
|
||||
"total_wh": 1793,
|
||||
"err_code": 0,
|
||||
},
|
||||
"context": "1",
|
||||
}
|
||||
@@ -1,24 +1,45 @@
|
||||
"""Tests for the TP-Link component."""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
import time
|
||||
from typing import Any
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from pyHS100 import SmartBulb, SmartDevice, SmartDeviceException, SmartPlug
|
||||
from pyHS100 import SmartBulb, SmartDevice, SmartDeviceException, SmartPlug, smartstrip
|
||||
from pyHS100.smartdevice import EmeterStatus
|
||||
import pytest
|
||||
|
||||
from homeassistant import config_entries, data_entry_flow
|
||||
from homeassistant.components import tplink
|
||||
from homeassistant.components.tplink.common import (
|
||||
from homeassistant.components.sensor import ATTR_LAST_RESET
|
||||
from homeassistant.components.switch import ATTR_CURRENT_POWER_W, ATTR_TODAY_ENERGY_KWH
|
||||
from homeassistant.components.tplink.common import SmartDevices
|
||||
from homeassistant.components.tplink.const import (
|
||||
ATTR_CURRENT_A,
|
||||
ATTR_TOTAL_ENERGY_KWH,
|
||||
CONF_DIMMER,
|
||||
CONF_DISCOVERY,
|
||||
CONF_EMETER_PARAMS,
|
||||
CONF_LIGHT,
|
||||
CONF_MODEL,
|
||||
CONF_SW_VERSION,
|
||||
CONF_SWITCH,
|
||||
COORDINATORS,
|
||||
)
|
||||
from homeassistant.const import CONF_HOST
|
||||
from homeassistant.const import (
|
||||
ATTR_VOLTAGE,
|
||||
CONF_ALIAS,
|
||||
CONF_DEVICE_ID,
|
||||
CONF_HOST,
|
||||
CONF_MAC,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.setup import async_setup_component
|
||||
from homeassistant.util.dt import utc_from_timestamp
|
||||
|
||||
from tests.common import MockConfigEntry, mock_coro
|
||||
from tests.components.tplink.consts import SMARTPLUGSWITCH_DATA, SMARTSTRIPWITCH_DATA
|
||||
|
||||
|
||||
async def test_creating_entry_tries_discover(hass):
|
||||
@@ -186,7 +207,7 @@ async def test_configuring_discovery_disabled(hass):
|
||||
assert mock_setup.call_count == 1
|
||||
|
||||
|
||||
async def test_platforms_are_initialized(hass):
|
||||
async def test_platforms_are_initialized(hass: HomeAssistant):
|
||||
"""Test that platforms are initialized per configuration array."""
|
||||
config = {
|
||||
tplink.DOMAIN: {
|
||||
@@ -199,6 +220,8 @@ async def test_platforms_are_initialized(hass):
|
||||
with patch(
|
||||
"homeassistant.components.tplink.common.Discover.discover"
|
||||
) as discover, patch(
|
||||
"homeassistant.components.tplink.get_static_devices"
|
||||
) as get_static_devices, patch(
|
||||
"homeassistant.components.tplink.common.SmartDevice._query_helper"
|
||||
), patch(
|
||||
"homeassistant.components.tplink.light.async_setup_entry",
|
||||
@@ -209,13 +232,141 @@ async def test_platforms_are_initialized(hass):
|
||||
) as switch_setup, patch(
|
||||
"homeassistant.components.tplink.common.SmartPlug.is_dimmable", False
|
||||
):
|
||||
|
||||
light = SmartBulb("123.123.123.123")
|
||||
switch = SmartPlug("321.321.321.321")
|
||||
switch.get_sysinfo = MagicMock(return_value=SMARTPLUGSWITCH_DATA["sysinfo"])
|
||||
switch.get_emeter_realtime = MagicMock(
|
||||
return_value=EmeterStatus(SMARTPLUGSWITCH_DATA["realtime"])
|
||||
)
|
||||
switch.get_emeter_daily = MagicMock(
|
||||
return_value={int(time.strftime("%e")): 1.123}
|
||||
)
|
||||
get_static_devices.return_value = SmartDevices([light], [switch])
|
||||
|
||||
# patching is_dimmable is necessray to avoid misdetection as light.
|
||||
await async_setup_component(hass, tplink.DOMAIN, config)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert discover.call_count == 0
|
||||
assert light_setup.call_count == 1
|
||||
assert switch_setup.call_count == 1
|
||||
assert hass.data.get(tplink.DOMAIN)
|
||||
assert hass.data[tplink.DOMAIN].get(COORDINATORS)
|
||||
assert hass.data[tplink.DOMAIN][COORDINATORS].get(switch.mac)
|
||||
assert isinstance(
|
||||
hass.data[tplink.DOMAIN][COORDINATORS][switch.mac],
|
||||
tplink.SmartPlugDataUpdateCoordinator,
|
||||
)
|
||||
data = hass.data[tplink.DOMAIN][COORDINATORS][switch.mac].data
|
||||
assert data[CONF_HOST] == switch.host
|
||||
assert data[CONF_MAC] == switch.sys_info["mac"]
|
||||
assert data[CONF_MODEL] == switch.sys_info["model"]
|
||||
assert data[CONF_SW_VERSION] == switch.sys_info["sw_ver"]
|
||||
assert data[CONF_ALIAS] == switch.sys_info["alias"]
|
||||
assert data[CONF_DEVICE_ID] == switch.sys_info["mac"]
|
||||
|
||||
emeter_readings = switch.get_emeter_realtime()
|
||||
assert data[CONF_EMETER_PARAMS][ATTR_VOLTAGE] == round(
|
||||
float(emeter_readings["voltage"]), 1
|
||||
)
|
||||
assert data[CONF_EMETER_PARAMS][ATTR_CURRENT_A] == round(
|
||||
float(emeter_readings["current"]), 2
|
||||
)
|
||||
assert data[CONF_EMETER_PARAMS][ATTR_CURRENT_POWER_W] == round(
|
||||
float(emeter_readings["power"]), 2
|
||||
)
|
||||
assert data[CONF_EMETER_PARAMS][ATTR_TOTAL_ENERGY_KWH] == round(
|
||||
float(emeter_readings["total"]), 3
|
||||
)
|
||||
assert data[CONF_EMETER_PARAMS][ATTR_LAST_RESET][
|
||||
ATTR_TOTAL_ENERGY_KWH
|
||||
] == utc_from_timestamp(0)
|
||||
|
||||
assert data[CONF_EMETER_PARAMS][ATTR_TODAY_ENERGY_KWH] == 1.123
|
||||
assert data[CONF_EMETER_PARAMS][ATTR_LAST_RESET][
|
||||
ATTR_TODAY_ENERGY_KWH
|
||||
] == datetime.utcnow().replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
|
||||
assert discover.call_count == 0
|
||||
assert get_static_devices.call_count == 1
|
||||
assert light_setup.call_count == 1
|
||||
assert switch_setup.call_count == 1
|
||||
|
||||
|
||||
async def test_smartplug_without_consumption_sensors(hass: HomeAssistant):
|
||||
"""Test that platforms are initialized per configuration array."""
|
||||
config = {
|
||||
tplink.DOMAIN: {
|
||||
CONF_DISCOVERY: False,
|
||||
CONF_SWITCH: [{CONF_HOST: "321.321.321.321"}],
|
||||
}
|
||||
}
|
||||
|
||||
with patch("homeassistant.components.tplink.common.Discover.discover"), patch(
|
||||
"homeassistant.components.tplink.get_static_devices"
|
||||
) as get_static_devices, patch(
|
||||
"homeassistant.components.tplink.common.SmartDevice._query_helper"
|
||||
), patch(
|
||||
"homeassistant.components.tplink.light.async_setup_entry",
|
||||
return_value=mock_coro(True),
|
||||
), patch(
|
||||
"homeassistant.components.tplink.switch.async_setup_entry",
|
||||
return_value=mock_coro(True),
|
||||
), patch(
|
||||
"homeassistant.components.tplink.sensor.SmartPlugSensor.__init__"
|
||||
) as SmartPlugSensor, patch(
|
||||
"homeassistant.components.tplink.common.SmartPlug.is_dimmable", False
|
||||
):
|
||||
|
||||
switch = SmartPlug("321.321.321.321")
|
||||
switch.get_sysinfo = MagicMock(return_value=SMARTPLUGSWITCH_DATA["sysinfo"])
|
||||
get_static_devices.return_value = SmartDevices([], [switch])
|
||||
|
||||
await async_setup_component(hass, tplink.DOMAIN, config)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert SmartPlugSensor.call_count == 0
|
||||
|
||||
|
||||
async def test_smartstrip_device(hass: HomeAssistant):
|
||||
"""Test discover a SmartStrip devices."""
|
||||
config = {
|
||||
tplink.DOMAIN: {
|
||||
CONF_DISCOVERY: True,
|
||||
}
|
||||
}
|
||||
|
||||
class SmartStrip(smartstrip.SmartStrip):
|
||||
"""Moked SmartStrip class."""
|
||||
|
||||
def get_sysinfo(self):
|
||||
return SMARTSTRIPWITCH_DATA["sysinfo"]
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.tplink.common.Discover.discover"
|
||||
) as discover, patch(
|
||||
"homeassistant.components.tplink.common.SmartDevice._query_helper"
|
||||
), patch(
|
||||
"homeassistant.components.tplink.common.SmartPlug.get_sysinfo",
|
||||
return_value=SMARTSTRIPWITCH_DATA["sysinfo"],
|
||||
), patch(
|
||||
"homeassistant.config_entries.ConfigEntries.async_forward_entry_setup"
|
||||
):
|
||||
|
||||
strip = SmartStrip("123.123.123.123")
|
||||
discover.return_value = {"123.123.123.123": strip}
|
||||
|
||||
assert await async_setup_component(hass, tplink.DOMAIN, config)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert hass.data.get(tplink.DOMAIN)
|
||||
assert hass.data[tplink.DOMAIN].get(COORDINATORS)
|
||||
assert hass.data[tplink.DOMAIN][COORDINATORS].get(strip.mac)
|
||||
assert isinstance(
|
||||
hass.data[tplink.DOMAIN][COORDINATORS][strip.mac],
|
||||
tplink.SmartPlugDataUpdateCoordinator,
|
||||
)
|
||||
data = hass.data[tplink.DOMAIN][COORDINATORS][strip.mac].data
|
||||
assert data[CONF_ALIAS] == strip.sys_info["children"][0]["alias"]
|
||||
assert data[CONF_DEVICE_ID] == "1"
|
||||
|
||||
|
||||
async def test_no_config_creates_no_entry(hass):
|
||||
@@ -230,6 +381,42 @@ async def test_no_config_creates_no_entry(hass):
|
||||
assert mock_setup.call_count == 0
|
||||
|
||||
|
||||
async def test_not_ready(hass: HomeAssistant):
|
||||
"""Test for not ready when configured devices are not available."""
|
||||
config = {
|
||||
tplink.DOMAIN: {
|
||||
CONF_DISCOVERY: False,
|
||||
CONF_SWITCH: [{CONF_HOST: "321.321.321.321"}],
|
||||
}
|
||||
}
|
||||
|
||||
with patch("homeassistant.components.tplink.common.Discover.discover"), patch(
|
||||
"homeassistant.components.tplink.get_static_devices"
|
||||
) as get_static_devices, patch(
|
||||
"homeassistant.components.tplink.common.SmartDevice._query_helper"
|
||||
), patch(
|
||||
"homeassistant.components.tplink.light.async_setup_entry",
|
||||
return_value=mock_coro(True),
|
||||
), patch(
|
||||
"homeassistant.components.tplink.switch.async_setup_entry",
|
||||
return_value=mock_coro(True),
|
||||
), patch(
|
||||
"homeassistant.components.tplink.common.SmartPlug.is_dimmable", False
|
||||
):
|
||||
|
||||
switch = SmartPlug("321.321.321.321")
|
||||
switch.get_sysinfo = MagicMock(side_effect=SmartDeviceException())
|
||||
get_static_devices.return_value = SmartDevices([], [switch])
|
||||
|
||||
await async_setup_component(hass, tplink.DOMAIN, config)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
entries = hass.config_entries.async_entries(tplink.DOMAIN)
|
||||
|
||||
assert len(entries) == 1
|
||||
assert entries[0].state is config_entries.ConfigEntryState.SETUP_RETRY
|
||||
|
||||
|
||||
@pytest.mark.parametrize("platform", ["switch", "light"])
|
||||
async def test_unload(hass, platform):
|
||||
"""Test that the async_unload_entry works."""
|
||||
@@ -238,21 +425,35 @@ async def test_unload(hass, platform):
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.tplink.get_static_devices"
|
||||
) as get_static_devices, patch(
|
||||
"homeassistant.components.tplink.common.SmartDevice._query_helper"
|
||||
), patch(
|
||||
f"homeassistant.components.tplink.{platform}.async_setup_entry",
|
||||
return_value=mock_coro(True),
|
||||
) as light_setup:
|
||||
) as async_setup_entry:
|
||||
config = {
|
||||
tplink.DOMAIN: {
|
||||
platform: [{CONF_HOST: "123.123.123.123"}],
|
||||
CONF_DISCOVERY: False,
|
||||
}
|
||||
}
|
||||
|
||||
light = SmartBulb("123.123.123.123")
|
||||
switch = SmartPlug("321.321.321.321")
|
||||
switch.get_sysinfo = MagicMock(return_value=SMARTPLUGSWITCH_DATA["sysinfo"])
|
||||
switch.get_emeter_realtime = MagicMock(
|
||||
return_value=EmeterStatus(SMARTPLUGSWITCH_DATA["realtime"])
|
||||
)
|
||||
if platform == "light":
|
||||
get_static_devices.return_value = SmartDevices([light], [])
|
||||
elif platform == "switch":
|
||||
get_static_devices.return_value = SmartDevices([], [switch])
|
||||
|
||||
assert await async_setup_component(hass, tplink.DOMAIN, config)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(light_setup.mock_calls) == 1
|
||||
assert len(async_setup_entry.mock_calls) == 1
|
||||
assert tplink.DOMAIN in hass.data
|
||||
|
||||
assert await tplink.async_unload_entry(hass, entry)
|
||||
|
||||
@@ -18,7 +18,7 @@ from homeassistant.components.light import (
|
||||
ATTR_HS_COLOR,
|
||||
DOMAIN as LIGHT_DOMAIN,
|
||||
)
|
||||
from homeassistant.components.tplink.common import (
|
||||
from homeassistant.components.tplink.const import (
|
||||
CONF_DIMMER,
|
||||
CONF_DISCOVERY,
|
||||
CONF_LIGHT,
|
||||
|
||||
Reference in New Issue
Block a user