Add Huawei LTE restart and clear traffic statistics buttons (#91967)
* Add Huawei LTE restart and clear traffic statistics buttons Deprecate corresponding services in favour of these. * Change to be removed service warnings to issues * Add tests * Update planned service remove versions
This commit is contained in:
parent
a1f7f899c9
commit
616f6aab76
7 changed files with 236 additions and 20 deletions
|
@ -50,6 +50,7 @@ from homeassistant.helpers.device_registry import DeviceInfo
|
|||
from homeassistant.helpers.dispatcher import async_dispatcher_connect, dispatcher_send
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.helpers.event import async_track_time_interval
|
||||
from homeassistant.helpers.issue_registry import IssueSeverity, create_issue
|
||||
from homeassistant.helpers.service import async_register_admin_service
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
|
||||
|
@ -57,6 +58,8 @@ from .const import (
|
|||
ADMIN_SERVICES,
|
||||
ALL_KEYS,
|
||||
ATTR_CONFIG_ENTRY_ID,
|
||||
BUTTON_KEY_CLEAR_TRAFFIC_STATISTICS,
|
||||
BUTTON_KEY_RESTART,
|
||||
CONF_MANUFACTURER,
|
||||
CONF_UNAUTHENTICATED_MODE,
|
||||
CONNECTION_TIMEOUT,
|
||||
|
@ -127,6 +130,7 @@ SERVICE_SCHEMA = vol.Schema({vol.Optional(CONF_URL): cv.url})
|
|||
|
||||
PLATFORMS = [
|
||||
Platform.BINARY_SENSOR,
|
||||
Platform.BUTTON,
|
||||
Platform.DEVICE_TRACKER,
|
||||
Platform.SENSOR,
|
||||
Platform.SWITCH,
|
||||
|
@ -524,12 +528,38 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|||
return
|
||||
|
||||
if service.service == SERVICE_CLEAR_TRAFFIC_STATISTICS:
|
||||
create_issue(
|
||||
hass,
|
||||
DOMAIN,
|
||||
"service_clear_traffic_statistics_moved_to_button",
|
||||
breaks_in_ha_version="2024.2.0",
|
||||
is_fixable=False,
|
||||
severity=IssueSeverity.WARNING,
|
||||
translation_key="service_changed_to_button",
|
||||
translation_placeholders={
|
||||
"service": service.service,
|
||||
"button": BUTTON_KEY_CLEAR_TRAFFIC_STATISTICS,
|
||||
},
|
||||
)
|
||||
if router.suspended:
|
||||
_LOGGER.debug("%s: ignored, integration suspended", service.service)
|
||||
return
|
||||
result = router.client.monitoring.set_clear_traffic()
|
||||
_LOGGER.debug("%s: %s", service.service, result)
|
||||
elif service.service == SERVICE_REBOOT:
|
||||
create_issue(
|
||||
hass,
|
||||
DOMAIN,
|
||||
"service_reboot_moved_to_button",
|
||||
breaks_in_ha_version="2024.2.0",
|
||||
is_fixable=False,
|
||||
severity=IssueSeverity.WARNING,
|
||||
translation_key="service_changed_to_button",
|
||||
translation_placeholders={
|
||||
"service": service.service,
|
||||
"button": BUTTON_KEY_RESTART,
|
||||
},
|
||||
)
|
||||
if router.suspended:
|
||||
_LOGGER.debug("%s: ignored, integration suspended", service.service)
|
||||
return
|
||||
|
|
97
homeassistant/components/huawei_lte/button.py
Normal file
97
homeassistant/components/huawei_lte/button.py
Normal file
|
@ -0,0 +1,97 @@
|
|||
"""Huawei LTE buttons."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from huawei_lte_api.enums.device import ControlModeEnum
|
||||
|
||||
from homeassistant.components.button import (
|
||||
ButtonDeviceClass,
|
||||
ButtonEntity,
|
||||
ButtonEntityDescription,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_platform
|
||||
|
||||
from . import HuaweiLteBaseEntityWithDevice
|
||||
from .const import DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: entity_platform.AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Huawei LTE buttons."""
|
||||
router = hass.data[DOMAIN].routers[config_entry.entry_id]
|
||||
buttons = [
|
||||
ClearTrafficStatisticsButton(router),
|
||||
RestartButton(router),
|
||||
]
|
||||
async_add_entities(buttons)
|
||||
|
||||
|
||||
class BaseButton(HuaweiLteBaseEntityWithDevice, ButtonEntity):
|
||||
"""Huawei LTE button base class."""
|
||||
|
||||
@property
|
||||
def _device_unique_id(self) -> str:
|
||||
"""Return unique ID for entity within a router."""
|
||||
return f"button-{self.entity_description.key}"
|
||||
|
||||
async def async_update(self) -> None:
|
||||
"""Update is not necessary for button entities."""
|
||||
|
||||
def press(self) -> None:
|
||||
"""Press button."""
|
||||
if self.router.suspended:
|
||||
_LOGGER.debug(
|
||||
"%s: ignored, integration suspended", self.entity_description.key
|
||||
)
|
||||
return
|
||||
result = self._press()
|
||||
_LOGGER.debug("%s: %s", self.entity_description.key, result)
|
||||
|
||||
def _press(self) -> str:
|
||||
"""Invoke low level action of button press."""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
BUTTON_KEY_CLEAR_TRAFFIC_STATISTICS = "clear_traffic_statistics"
|
||||
|
||||
|
||||
class ClearTrafficStatisticsButton(BaseButton):
|
||||
"""Huawei LTE clear traffic statistics button."""
|
||||
|
||||
entity_description = ButtonEntityDescription(
|
||||
key=BUTTON_KEY_CLEAR_TRAFFIC_STATISTICS,
|
||||
name="Clear traffic statistics",
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
)
|
||||
|
||||
def _press(self) -> str:
|
||||
"""Call clear traffic statistics endpoint."""
|
||||
return self.router.client.monitoring.set_clear_traffic()
|
||||
|
||||
|
||||
BUTTON_KEY_RESTART = "restart"
|
||||
|
||||
|
||||
class RestartButton(BaseButton):
|
||||
"""Huawei LTE restart button."""
|
||||
|
||||
entity_description = ButtonEntityDescription(
|
||||
key=BUTTON_KEY_RESTART,
|
||||
name="Restart",
|
||||
device_class=ButtonDeviceClass.RESTART,
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
)
|
||||
|
||||
def _press(self) -> str:
|
||||
"""Call restart endpoint."""
|
||||
return self.router.client.device.set_control(ControlModeEnum.REBOOT)
|
|
@ -79,3 +79,6 @@ ALL_KEYS = (
|
|||
| SWITCH_KEYS
|
||||
| {KEY_DEVICE_BASIC_INFORMATION}
|
||||
)
|
||||
|
||||
BUTTON_KEY_CLEAR_TRAFFIC_STATISTICS = "clear_traffic_statistics"
|
||||
BUTTON_KEY_RESTART = "restart"
|
||||
|
|
|
@ -279,6 +279,12 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"issues": {
|
||||
"service_changed_to_button": {
|
||||
"title": "Service changed to a button",
|
||||
"description": "The {service} service is deprecated, use the corresponding {button} button instead."
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
"clear_traffic_statistics": {
|
||||
"name": "Clear traffic statistics",
|
||||
|
|
|
@ -1 +1,23 @@
|
|||
"""Tests for the huawei_lte component."""
|
||||
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from huawei_lte_api.enums.cradle import ConnectionStatusEnum
|
||||
|
||||
|
||||
def magic_client(multi_basic_settings_value: dict) -> MagicMock:
|
||||
"""Mock huawei_lte.Client."""
|
||||
information = MagicMock(return_value={"SerialNumber": "test-serial-number"})
|
||||
check_notifications = MagicMock(return_value={"SmsStorageFull": 0})
|
||||
status = MagicMock(
|
||||
return_value={"ConnectionStatus": ConnectionStatusEnum.CONNECTED.value}
|
||||
)
|
||||
multi_basic_settings = MagicMock(return_value=multi_basic_settings_value)
|
||||
wifi_feature_switch = MagicMock(return_value={"wifi24g_switch_enable": 1})
|
||||
device = MagicMock(information=information)
|
||||
monitoring = MagicMock(check_notifications=check_notifications, status=status)
|
||||
wlan = MagicMock(
|
||||
multi_basic_settings=multi_basic_settings,
|
||||
wifi_feature_switch=wifi_feature_switch,
|
||||
)
|
||||
return MagicMock(device=device, monitoring=monitoring, wlan=wlan)
|
||||
|
|
76
tests/components/huawei_lte/test_button.py
Normal file
76
tests/components/huawei_lte/test_button.py
Normal file
|
@ -0,0 +1,76 @@
|
|||
"""Tests for the Huawei LTE switches."""
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from huawei_lte_api.enums.device import ControlModeEnum
|
||||
|
||||
from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN, SERVICE_PRESS
|
||||
from homeassistant.components.huawei_lte.const import (
|
||||
BUTTON_KEY_CLEAR_TRAFFIC_STATISTICS,
|
||||
BUTTON_KEY_RESTART,
|
||||
DOMAIN,
|
||||
SERVICE_SUSPEND_INTEGRATION,
|
||||
)
|
||||
from homeassistant.const import ATTR_ENTITY_ID, CONF_URL
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from . import magic_client
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
MOCK_CONF_URL = "http://huawei-lte.example.com"
|
||||
|
||||
|
||||
@patch("homeassistant.components.huawei_lte.Connection", MagicMock())
|
||||
@patch("homeassistant.components.huawei_lte.Client", return_value=magic_client({}))
|
||||
async def test_clear_traffic_statistics(client, hass: HomeAssistant) -> None:
|
||||
"""Test clear traffic statistics button."""
|
||||
huawei_lte = MockConfigEntry(domain=DOMAIN, data={CONF_URL: MOCK_CONF_URL})
|
||||
huawei_lte.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(huawei_lte.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
await hass.services.async_call(
|
||||
BUTTON_DOMAIN,
|
||||
SERVICE_PRESS,
|
||||
{ATTR_ENTITY_ID: f"button.lte_{BUTTON_KEY_CLEAR_TRAFFIC_STATISTICS}"},
|
||||
blocking=True,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
client.return_value.monitoring.set_clear_traffic.assert_called_once()
|
||||
|
||||
client.return_value.monitoring.set_clear_traffic.reset_mock()
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
SERVICE_SUSPEND_INTEGRATION,
|
||||
{CONF_URL: MOCK_CONF_URL},
|
||||
blocking=True,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
client.return_value.monitoring.set_clear_traffic.assert_not_called()
|
||||
|
||||
|
||||
@patch("homeassistant.components.huawei_lte.Connection", MagicMock())
|
||||
@patch("homeassistant.components.huawei_lte.Client", return_value=magic_client({}))
|
||||
async def test_restart(client, hass: HomeAssistant) -> None:
|
||||
"""Test restart button."""
|
||||
huawei_lte = MockConfigEntry(domain=DOMAIN, data={CONF_URL: MOCK_CONF_URL})
|
||||
huawei_lte.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(huawei_lte.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
await hass.services.async_call(
|
||||
BUTTON_DOMAIN,
|
||||
SERVICE_PRESS,
|
||||
{ATTR_ENTITY_ID: f"button.lte_{BUTTON_KEY_RESTART}"},
|
||||
blocking=True,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
client.return_value.device.set_control.assert_called_with(ControlModeEnum.REBOOT)
|
||||
|
||||
client.return_value.device.set_control.reset_mock()
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
SERVICE_SUSPEND_INTEGRATION,
|
||||
{CONF_URL: MOCK_CONF_URL},
|
||||
blocking=True,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
client.return_value.device.set_control.assert_not_called()
|
|
@ -1,8 +1,6 @@
|
|||
"""Tests for the Huawei LTE switches."""
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from huawei_lte_api.enums.cradle import ConnectionStatusEnum
|
||||
|
||||
from homeassistant.components.huawei_lte.const import DOMAIN
|
||||
from homeassistant.components.switch import (
|
||||
DOMAIN as SWITCH_DOMAIN,
|
||||
|
@ -13,29 +11,13 @@ from homeassistant.const import ATTR_ENTITY_ID, CONF_URL, STATE_OFF, STATE_ON
|
|||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from . import magic_client
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
SWITCH_WIFI_GUEST_NETWORK = "switch.lte_wi_fi_guest_network"
|
||||
|
||||
|
||||
def magic_client(multi_basic_settings_value: dict) -> MagicMock:
|
||||
"""Mock huawei_lte.Client."""
|
||||
information = MagicMock(return_value={"SerialNumber": "test-serial-number"})
|
||||
check_notifications = MagicMock(return_value={"SmsStorageFull": 0})
|
||||
status = MagicMock(
|
||||
return_value={"ConnectionStatus": ConnectionStatusEnum.CONNECTED.value}
|
||||
)
|
||||
multi_basic_settings = MagicMock(return_value=multi_basic_settings_value)
|
||||
wifi_feature_switch = MagicMock(return_value={"wifi24g_switch_enable": 1})
|
||||
device = MagicMock(information=information)
|
||||
monitoring = MagicMock(check_notifications=check_notifications, status=status)
|
||||
wlan = MagicMock(
|
||||
multi_basic_settings=multi_basic_settings,
|
||||
wifi_feature_switch=wifi_feature_switch,
|
||||
)
|
||||
return MagicMock(device=device, monitoring=monitoring, wlan=wlan)
|
||||
|
||||
|
||||
@patch("homeassistant.components.huawei_lte.Connection", MagicMock())
|
||||
@patch("homeassistant.components.huawei_lte.Client", return_value=magic_client({}))
|
||||
async def test_huawei_lte_wifi_guest_network_config_entry_when_network_is_not_present(
|
||||
|
|
Loading…
Add table
Reference in a new issue