1
0
mirror of https://github.com/home-assistant/core.git synced 2026-05-08 17:49:37 +01:00

Bump pyuptimerobot to 25.0.0 (#169572)

This commit is contained in:
Simone Chemelli
2026-05-04 17:13:55 +02:00
committed by GitHub
parent 2521f6d825
commit 14aa87f026
11 changed files with 86 additions and 48 deletions
@@ -8,5 +8,5 @@
"iot_class": "cloud_polling",
"loggers": ["pyuptimerobot"],
"quality_scale": "gold",
"requirements": ["pyuptimerobot==24.0.1"]
"requirements": ["pyuptimerobot==25.0.0"]
}
@@ -59,9 +59,12 @@ class UptimeRobotSensor(UptimeRobotEntity, SensorEntity):
"""Representation of a UptimeRobot sensor."""
@property
def native_value(self) -> str:
def native_value(self) -> str | None:
"""Return the status of the monitor."""
if not self._monitor.status:
return None
status = self._monitor.status.lower()
# The API returns "paused"
# but the entity state will be "pause" to avoid a breaking change
return {"paused": "pause"}.get(status, status) # type: ignore[no-any-return]
return {"paused": "pause"}.get(status, status)
+9 -26
View File
@@ -2,11 +2,7 @@
from typing import Any
from pyuptimerobot import (
UptimeRobotAuthenticationException,
UptimeRobotException,
UptimeRobotMonitor,
)
from pyuptimerobot import UptimeRobotMonitor
from homeassistant.components.switch import (
SwitchDeviceClass,
@@ -14,13 +10,12 @@ from homeassistant.components.switch import (
SwitchEntityDescription,
)
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from .const import DOMAIN, STATUS_DOWN, STATUS_UP
from .const import STATUS_UP
from .coordinator import UptimeRobotConfigEntry
from .entity import UptimeRobotEntity
from .utils import new_device_listener
from .utils import new_device_listener, uptimerobot_api_call
# Limit the number of parallel updates to 1
PARALLEL_UPDATES = 1
@@ -63,26 +58,14 @@ class UptimeRobotSwitch(UptimeRobotEntity, SwitchEntity):
"""Return True if the entity is on."""
return bool(self._monitor.status == STATUS_UP)
async def _async_edit_monitor(self, **kwargs: Any) -> None:
"""Edit monitor status."""
try:
await self.api.async_edit_monitor(**kwargs)
except UptimeRobotAuthenticationException:
self.coordinator.config_entry.async_start_reauth(self.hass)
return
except UptimeRobotException as exception:
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="api_exception",
translation_placeholders={"error": "Generic UptimeRobot exception"},
) from exception
await self.coordinator.async_request_refresh()
@uptimerobot_api_call
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn off switch."""
await self._async_edit_monitor(monitor_id=self._monitor.id, status=STATUS_DOWN)
await self.api.async_pause_monitor(monitor_id=self._monitor.id)
await self.coordinator.async_request_refresh()
@uptimerobot_api_call
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn on switch."""
await self._async_edit_monitor(monitor_id=self._monitor.id, status=STATUS_UP)
await self.api.async_start_monitor(monitor_id=self._monitor.id)
await self.coordinator.async_request_refresh()
+35 -2
View File
@@ -1,10 +1,43 @@
"""Utility functions for the UptimeRobot integration."""
from collections.abc import Callable
from collections.abc import Awaitable, Callable, Coroutine
from functools import wraps
from typing import Any, Concatenate
from pyuptimerobot import UptimeRobotMonitor
from pyuptimerobot import (
UptimeRobotAuthenticationException,
UptimeRobotException,
UptimeRobotMonitor,
)
from homeassistant.exceptions import HomeAssistantError
from .const import DOMAIN
from .coordinator import UptimeRobotDataUpdateCoordinator
from .entity import UptimeRobotEntity
def uptimerobot_api_call[_T: UptimeRobotEntity, **_P](
func: Callable[Concatenate[_T, _P], Awaitable[None]],
) -> Callable[Concatenate[_T, _P], Coroutine[Any, Any, None]]:
"""Catch UptimeRobot API call exceptions."""
@wraps(func)
async def cmd_wrapper(self: _T, *args: _P.args, **kwargs: _P.kwargs) -> None:
"""Wrap all command methods."""
try:
await func(self, *args, **kwargs)
except UptimeRobotAuthenticationException:
self.coordinator.config_entry.async_start_reauth(self.hass)
return
except UptimeRobotException as exception:
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="api_exception",
translation_placeholders={"error": "Generic UptimeRobot exception"},
) from exception
return cmd_wrapper
def new_device_listener(
+1 -1
View File
@@ -2739,7 +2739,7 @@ pytrafikverket==1.1.1
pytrydan==0.8.0
# homeassistant.components.uptimerobot
pyuptimerobot==24.0.1
pyuptimerobot==25.0.0
# homeassistant.components.vera
pyvera==0.3.16
+1 -1
View File
@@ -2338,7 +2338,7 @@ pytrafikverket==1.1.1
pytrydan==0.8.0
# homeassistant.components.uptimerobot
pyuptimerobot==24.0.1
pyuptimerobot==25.0.0
# homeassistant.components.vera
pyvera==0.3.16
+2 -1
View File
@@ -4,7 +4,8 @@ from enum import StrEnum
from typing import Any
from unittest.mock import patch
from pyuptimerobot import API_PATH_MONITORS, UptimeRobotApiResponse
from pyuptimerobot import UptimeRobotApiResponse
from pyuptimerobot.const import API_PATH_MONITORS
from homeassistant import config_entries
from homeassistant.components.uptimerobot.const import DOMAIN
@@ -4,11 +4,11 @@ from unittest.mock import patch
import pytest
from pyuptimerobot import (
API_PATH_USER_ME,
UptimeRobotAuthenticationException,
UptimeRobotConnectionException,
UptimeRobotException,
)
from pyuptimerobot.const import API_PATH_USER_ME
from homeassistant import config_entries
from homeassistant.components.uptimerobot.const import DOMAIN
@@ -3,7 +3,8 @@
import json
from unittest.mock import patch
from pyuptimerobot import API_PATH_USER_ME, UptimeRobotException
from pyuptimerobot import UptimeRobotException
from pyuptimerobot.const import API_PATH_USER_ME
from homeassistant.core import HomeAssistant
+22 -2
View File
@@ -6,11 +6,12 @@ from pyuptimerobot import UptimeRobotAuthenticationException
from homeassistant.components.sensor import SensorDeviceClass
from homeassistant.components.uptimerobot.const import COORDINATOR_UPDATE_INTERVAL
from homeassistant.const import STATE_UNAVAILABLE
from homeassistant.const import STATE_UNAVAILABLE, STATE_UNKNOWN
from homeassistant.core import HomeAssistant
from homeassistant.util import dt as dt_util
from .common import (
MOCK_UPTIMEROBOT_CONFIG_ENTRY_DATA,
MOCK_UPTIMEROBOT_MONITOR,
MOCK_UPTIMEROBOT_MONITOR_2,
STATE_UP,
@@ -19,7 +20,7 @@ from .common import (
setup_uptimerobot_integration,
)
from tests.common import async_fire_time_changed
from tests.common import MockConfigEntry, async_fire_time_changed
async def test_presentation(hass: HomeAssistant) -> None:
@@ -83,3 +84,22 @@ async def test_sensor_dynamic(hass: HomeAssistant) -> None:
assert (entity := hass.states.get(entity_id_2))
assert entity.state == STATE_UP
async def test_sensor_monitor_status_missing(
hass: HomeAssistant,
) -> None:
"""Test sensor becomes unknown when the monitor status is missing."""
monitor_without_status = {**MOCK_UPTIMEROBOT_MONITOR, "status": None}
mock_entry = MockConfigEntry(**MOCK_UPTIMEROBOT_CONFIG_ENTRY_DATA)
mock_entry.add_to_hass(hass)
with patch(
"pyuptimerobot.UptimeRobot.async_get_monitors",
return_value=mock_uptimerobot_api_response(data=[monitor_without_status]),
):
assert await hass.config_entries.async_setup(mock_entry.entry_id)
await hass.async_block_till_done()
assert (entity := hass.states.get(UPTIMEROBOT_SENSOR_TEST_ENTITY))
assert entity.state == STATE_UNKNOWN
+7 -10
View File
@@ -3,11 +3,8 @@
from unittest.mock import patch
import pytest
from pyuptimerobot import (
API_PATH_MONITOR_DETAIL,
UptimeRobotAuthenticationException,
UptimeRobotException,
)
from pyuptimerobot import UptimeRobotAuthenticationException, UptimeRobotException
from pyuptimerobot.const import API_PATH_MONITOR_DETAIL
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
from homeassistant.components.uptimerobot.const import COORDINATOR_UPDATE_INTERVAL
@@ -58,7 +55,7 @@ async def test_switch_off(hass: HomeAssistant) -> None:
),
),
patch(
"pyuptimerobot.UptimeRobot.async_edit_monitor",
"pyuptimerobot.UptimeRobot.async_pause_monitor",
return_value=mock_uptimerobot_api_response(
api_path=API_PATH_MONITOR_DETAIL, data=MOCK_UPTIMEROBOT_MONITOR_PAUSED
),
@@ -90,7 +87,7 @@ async def test_switch_on(hass: HomeAssistant) -> None:
return_value=mock_uptimerobot_api_response(data=[MOCK_UPTIMEROBOT_MONITOR]),
),
patch(
"pyuptimerobot.UptimeRobot.async_edit_monitor",
"pyuptimerobot.UptimeRobot.async_start_monitor",
return_value=mock_uptimerobot_api_response(
api_path=API_PATH_MONITOR_DETAIL,
data=MOCK_UPTIMEROBOT_MONITOR,
@@ -122,7 +119,7 @@ async def test_authentication_error(
with (
patch(
"pyuptimerobot.UptimeRobot.async_edit_monitor",
"pyuptimerobot.UptimeRobot.async_start_monitor",
side_effect=UptimeRobotAuthenticationException,
),
patch(
@@ -148,7 +145,7 @@ async def test_action_execution_failure(hass: HomeAssistant) -> None:
with (
patch(
"pyuptimerobot.UptimeRobot.async_edit_monitor",
"pyuptimerobot.UptimeRobot.async_start_monitor",
side_effect=UptimeRobotException,
),
pytest.raises(HomeAssistantError) as exc_info,
@@ -176,7 +173,7 @@ async def test_switch_api_failure(hass: HomeAssistant) -> None:
with (
patch(
"pyuptimerobot.UptimeRobot.async_edit_monitor",
"pyuptimerobot.UptimeRobot.async_pause_monitor",
side_effect=UptimeRobotException,
),
pytest.raises(HomeAssistantError) as exc_info,