Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions homeassistant/components/lg_netcast/media_player.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Support for LG TV running on NetCast 3 or 4."""

from collections import Counter
from datetime import datetime
import time
from typing import TYPE_CHECKING, Any, override

from pylgnetcast import LG_COMMAND, LgNetCastError
Expand Down Expand Up @@ -223,9 +223,7 @@ def supported_features(self) -> MediaPlayerEntityFeature:
@override
def media_image_url(self):
"""URL for obtaining a screen capture."""
return (
f"{self._client.url}data?target=screen_image&_={datetime.now().timestamp()}" # pylint: disable=home-assistant-enforce-naive-now
)
return f"{self._client.url}data?target=screen_image&_={time.time()}"

@override
def turn_off(self) -> None:
Expand Down
5 changes: 2 additions & 3 deletions homeassistant/components/nanoleaf/light.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,8 @@ def effect(self) -> str | None:
# The effects *Static* and *Dynamic* are not supported by Home Assistant.
# These reserved effects are implicitly set and are not in the effect_list.
# https://forum.nanoleaf.me/docs/openapi#_byoot0bams8f
return (
None if self._nanoleaf.effect in RESERVED_EFFECTS else self._nanoleaf.effect
)
effect = self._nanoleaf.effect
return None if not effect or effect in RESERVED_EFFECTS else effect

@property
@override
Expand Down
17 changes: 12 additions & 5 deletions homeassistant/components/netatmo/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ class NetatmoPublisher:
kwargs: dict
available: bool = True
error_count: int = 0
unavailable_logged: bool = False


class NetatmoDataHandler:
Expand Down Expand Up @@ -262,22 +263,28 @@ async def handle_event(self, event: dict) -> None:
async def async_fetch_data(self, signal_name: str) -> bool:
"""Fetch data and notify."""
self.poll_count += 1
publisher = self.publisher[signal_name]
has_error = False
try:
await getattr(self.account, self.publisher[signal_name].method)(
**self.publisher[signal_name].kwargs
)
await getattr(self.account, publisher.method)(**publisher.kwargs)

except (
pyatmo.NoDeviceError,
pyatmo.ApiError,
TimeoutError,
aiohttp.ClientConnectorError,
) as err:
_LOGGER.debug(err)
has_error = True
if not publisher.unavailable_logged:
_LOGGER.info("Error while fetching %s data: %s", signal_name, err)
publisher.unavailable_logged = True
else:
_LOGGER.debug(err)
else:
if publisher.unavailable_logged:
_LOGGER.info("Fetching %s data recovered", signal_name)
publisher.unavailable_logged = False

publisher = self.publisher[signal_name]
if has_error:
publisher.error_count += 1
else:
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/netatmo/quality_scale.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ rules:
docs-installation-parameters: todo
entity-unavailable: done
integration-owner: done
log-when-unavailable: todo
log-when-unavailable: done
parallel-updates: done
reauthentication-flow: done
test-coverage: todo
Expand Down
6 changes: 3 additions & 3 deletions homeassistant/components/nice_go/config_flow.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"""Config flow for Nice G.O. integration."""

from collections.abc import Mapping
from datetime import datetime
import logging
import time
from typing import Any, override

from nice_go import AuthFailedError, NiceGOApi
Expand Down Expand Up @@ -59,7 +59,7 @@ async def async_step_user(
CONF_EMAIL: user_input[CONF_EMAIL],
CONF_PASSWORD: user_input[CONF_PASSWORD],
CONF_REFRESH_TOKEN: refresh_token,
CONF_REFRESH_TOKEN_CREATION_TIME: datetime.now().timestamp(), # pylint: disable=home-assistant-enforce-naive-now
CONF_REFRESH_TOKEN_CREATION_TIME: time.time(),
},
)

Expand Down Expand Up @@ -100,7 +100,7 @@ async def async_step_reauth_confirm(
data={
**user_input,
CONF_REFRESH_TOKEN: refresh_token,
CONF_REFRESH_TOKEN_CREATION_TIME: datetime.now().timestamp(), # pylint: disable=home-assistant-enforce-naive-now
CONF_REFRESH_TOKEN_CREATION_TIME: time.time(),
},
unique_id=user_input[CONF_EMAIL],
)
Expand Down
6 changes: 3 additions & 3 deletions homeassistant/components/nice_go/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
import asyncio
from collections.abc import Callable
from dataclasses import dataclass
from datetime import datetime
import json
import logging
import time
from typing import TYPE_CHECKING, Any, override

from nice_go import (
Expand Down Expand Up @@ -174,7 +174,7 @@ async def authenticate(self) -> None:
self.refresh_token_creation_time + REFRESH_TOKEN_EXPIRY_TIME.total_seconds()
)
try:
if datetime.now().timestamp() >= expiry_time: # pylint: disable=home-assistant-enforce-naive-now
if time.time() >= expiry_time:
await self.update_refresh_token()
else:
await self.api.authenticate_refresh(
Expand Down Expand Up @@ -205,7 +205,7 @@ async def update_refresh_token(self) -> None:
data = {
**self.config_entry.data,
CONF_REFRESH_TOKEN: refresh_token,
CONF_REFRESH_TOKEN_CREATION_TIME: datetime.now().timestamp(), # pylint: disable=home-assistant-enforce-naive-now
CONF_REFRESH_TOKEN_CREATION_TIME: time.time(),
}
self.hass.config_entries.async_update_entry(self.config_entry, data=data)

Expand Down
32 changes: 31 additions & 1 deletion tests/components/nanoleaf/test_light.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
import pytest
from syrupy.assertion import SnapshotAssertion

from homeassistant.components.light import ATTR_EFFECT_LIST, DOMAIN as LIGHT_DOMAIN
from homeassistant.components.light import (
ATTR_EFFECT,
ATTR_EFFECT_LIST,
DOMAIN as LIGHT_DOMAIN,
)
from homeassistant.const import (
ATTR_ENTITY_ID,
SERVICE_TURN_OFF,
Expand Down Expand Up @@ -66,3 +70,29 @@ async def test_turning_on_or_off_writes_state(
"Nemo",
"Something Else",
]


@pytest.mark.parametrize(
("effect", "expected_effect"),
[
("", None),
("*Solid*", None),
("Rainbow", "Rainbow"),
],
)
async def test_effect(
hass: HomeAssistant,
mock_nanoleaf: AsyncMock,
mock_config_entry: MockConfigEntry,
effect: str,
expected_effect: str | None,
) -> None:
"""Test the current effect."""
mock_nanoleaf.is_on = True
mock_nanoleaf.effect = effect

await setup_integration(hass, mock_config_entry)

state = hass.states.get("light.nanoleaf")
assert state is not None
assert state.attributes.get(ATTR_EFFECT) == expected_effect
43 changes: 43 additions & 0 deletions tests/components/netatmo/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from datetime import timedelta
from functools import partial
from itertools import pairwise
import logging
from time import time
from typing import Any
from unittest.mock import AsyncMock, patch
Expand All @@ -18,6 +19,7 @@

from homeassistant.components import cloud, webhook
from homeassistant.components.netatmo import DOMAIN, coordinator
from homeassistant.components.netatmo.coordinator import ACCOUNT
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import (
CONF_WEBHOOK_ID,
Expand Down Expand Up @@ -1197,3 +1199,44 @@ async def fake_post(*args: Any, **kwargs: Any):
# scheduled update), the delay then doubles per consecutive error until the
# patched cap of 600s is reached
assert gaps == [180, 300, 600, 600]


async def test_log_when_unavailable(
hass: HomeAssistant,
config_entry: MockConfigEntry,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test that unavailability and recovery are each logged exactly once."""
with (
patch(
"homeassistant.components.netatmo.api.AsyncConfigEntryNetatmoAuth"
) as mock_auth,
patch(
"homeassistant.components.netatmo.async_get_config_entry_implementation",
return_value=AsyncMock(),
),
patch("homeassistant.components.netatmo.webhook.webhook_generate_url"),
):
post_request = mock_auth.return_value.async_post_api_request
post_request.side_effect = partial(fake_post_request, hass)
mock_auth.return_value.async_addwebhook.side_effect = AsyncMock()
mock_auth.return_value.async_dropwebhook.side_effect = AsyncMock()
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()

data_handler = config_entry.runtime_data

with caplog.at_level(
logging.INFO, logger="homeassistant.components.netatmo.coordinator"
):
post_request.side_effect = pyatmo.ApiError("boom")
await data_handler.async_fetch_data(ACCOUNT)
await data_handler.async_fetch_data(ACCOUNT)

assert caplog.text.count("Error while fetching") == 1

post_request.side_effect = partial(fake_post_request, hass)
await data_handler.async_fetch_data(ACCOUNT)
await data_handler.async_fetch_data(ACCOUNT)

assert caplog.text.count("recovered") == 1
4 changes: 2 additions & 2 deletions tests/components/nice_go/conftest.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Common fixtures for the Nice G.O. tests."""

from collections.abc import Generator
from datetime import datetime
import time
from unittest.mock import AsyncMock, patch

from nice_go import Barrier, BarrierState, ConnectionState
Expand Down Expand Up @@ -74,7 +74,7 @@ def mock_config_entry() -> MockConfigEntry:
CONF_EMAIL: "test-email",
CONF_PASSWORD: "test-password",
CONF_REFRESH_TOKEN: "test-refresh-token",
CONF_REFRESH_TOKEN_CREATION_TIME: datetime.now().timestamp(), # pylint: disable=home-assistant-enforce-naive-now
CONF_REFRESH_TOKEN_CREATION_TIME: time.time(),
},
version=1,
unique_id="test-email",
Expand Down
Loading