Fix PVOutput when no data is available (#66338)
This commit is contained in:
parent
df994a1e84
commit
8ff987d90c
7 changed files with 30 additions and 22 deletions
|
@ -23,7 +23,7 @@ async def validate_input(hass: HomeAssistant, *, api_key: str, system_id: int) -
|
||||||
api_key=api_key,
|
api_key=api_key,
|
||||||
system_id=system_id,
|
system_id=system_id,
|
||||||
)
|
)
|
||||||
await pvoutput.status()
|
await pvoutput.system()
|
||||||
|
|
||||||
|
|
||||||
class PVOutputFlowHandler(ConfigFlow, domain=DOMAIN):
|
class PVOutputFlowHandler(ConfigFlow, domain=DOMAIN):
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
"""DataUpdateCoordinator for the PVOutput integration."""
|
"""DataUpdateCoordinator for the PVOutput integration."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pvo import PVOutput, PVOutputAuthenticationError, Status
|
from pvo import PVOutput, PVOutputAuthenticationError, PVOutputNoDataError, Status
|
||||||
|
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import CONF_API_KEY
|
from homeassistant.const import CONF_API_KEY
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import ConfigEntryAuthFailed
|
from homeassistant.exceptions import ConfigEntryAuthFailed
|
||||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||||
|
|
||||||
from .const import CONF_SYSTEM_ID, DOMAIN, LOGGER, SCAN_INTERVAL
|
from .const import CONF_SYSTEM_ID, DOMAIN, LOGGER, SCAN_INTERVAL
|
||||||
|
|
||||||
|
@ -33,5 +33,7 @@ class PVOutputDataUpdateCoordinator(DataUpdateCoordinator[Status]):
|
||||||
"""Fetch system status from PVOutput."""
|
"""Fetch system status from PVOutput."""
|
||||||
try:
|
try:
|
||||||
return await self.pvoutput.status()
|
return await self.pvoutput.status()
|
||||||
|
except PVOutputNoDataError as err:
|
||||||
|
raise UpdateFailed("PVOutput has no data available") from err
|
||||||
except PVOutputAuthenticationError as err:
|
except PVOutputAuthenticationError as err:
|
||||||
raise ConfigEntryAuthFailed from err
|
raise ConfigEntryAuthFailed from err
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
"documentation": "https://www.home-assistant.io/integrations/pvoutput",
|
"documentation": "https://www.home-assistant.io/integrations/pvoutput",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"codeowners": ["@fabaff", "@frenck"],
|
"codeowners": ["@fabaff", "@frenck"],
|
||||||
"requirements": ["pvo==0.2.1"],
|
"requirements": ["pvo==0.2.2"],
|
||||||
"iot_class": "cloud_polling",
|
"iot_class": "cloud_polling",
|
||||||
"quality_scale": "platinum"
|
"quality_scale": "platinum"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1313,7 +1313,7 @@ pushbullet.py==0.11.0
|
||||||
pushover_complete==1.1.1
|
pushover_complete==1.1.1
|
||||||
|
|
||||||
# homeassistant.components.pvoutput
|
# homeassistant.components.pvoutput
|
||||||
pvo==0.2.1
|
pvo==0.2.2
|
||||||
|
|
||||||
# homeassistant.components.rpi_gpio_pwm
|
# homeassistant.components.rpi_gpio_pwm
|
||||||
pwmled==1.6.9
|
pwmled==1.6.9
|
||||||
|
|
|
@ -820,7 +820,7 @@ pure-python-adb[async]==0.3.0.dev0
|
||||||
pushbullet.py==0.11.0
|
pushbullet.py==0.11.0
|
||||||
|
|
||||||
# homeassistant.components.pvoutput
|
# homeassistant.components.pvoutput
|
||||||
pvo==0.2.1
|
pvo==0.2.2
|
||||||
|
|
||||||
# homeassistant.components.canary
|
# homeassistant.components.canary
|
||||||
py-canary==0.5.1
|
py-canary==0.5.1
|
||||||
|
|
|
@ -47,7 +47,7 @@ async def test_full_user_flow(
|
||||||
}
|
}
|
||||||
|
|
||||||
assert len(mock_setup_entry.mock_calls) == 1
|
assert len(mock_setup_entry.mock_calls) == 1
|
||||||
assert len(mock_pvoutput_config_flow.status.mock_calls) == 1
|
assert len(mock_pvoutput_config_flow.system.mock_calls) == 1
|
||||||
|
|
||||||
|
|
||||||
async def test_full_flow_with_authentication_error(
|
async def test_full_flow_with_authentication_error(
|
||||||
|
@ -68,7 +68,7 @@ async def test_full_flow_with_authentication_error(
|
||||||
assert result.get("step_id") == SOURCE_USER
|
assert result.get("step_id") == SOURCE_USER
|
||||||
assert "flow_id" in result
|
assert "flow_id" in result
|
||||||
|
|
||||||
mock_pvoutput_config_flow.status.side_effect = PVOutputAuthenticationError
|
mock_pvoutput_config_flow.system.side_effect = PVOutputAuthenticationError
|
||||||
result2 = await hass.config_entries.flow.async_configure(
|
result2 = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
user_input={
|
user_input={
|
||||||
|
@ -83,9 +83,9 @@ async def test_full_flow_with_authentication_error(
|
||||||
assert "flow_id" in result2
|
assert "flow_id" in result2
|
||||||
|
|
||||||
assert len(mock_setup_entry.mock_calls) == 0
|
assert len(mock_setup_entry.mock_calls) == 0
|
||||||
assert len(mock_pvoutput_config_flow.status.mock_calls) == 1
|
assert len(mock_pvoutput_config_flow.system.mock_calls) == 1
|
||||||
|
|
||||||
mock_pvoutput_config_flow.status.side_effect = None
|
mock_pvoutput_config_flow.system.side_effect = None
|
||||||
result3 = await hass.config_entries.flow.async_configure(
|
result3 = await hass.config_entries.flow.async_configure(
|
||||||
result2["flow_id"],
|
result2["flow_id"],
|
||||||
user_input={
|
user_input={
|
||||||
|
@ -102,14 +102,14 @@ async def test_full_flow_with_authentication_error(
|
||||||
}
|
}
|
||||||
|
|
||||||
assert len(mock_setup_entry.mock_calls) == 1
|
assert len(mock_setup_entry.mock_calls) == 1
|
||||||
assert len(mock_pvoutput_config_flow.status.mock_calls) == 2
|
assert len(mock_pvoutput_config_flow.system.mock_calls) == 2
|
||||||
|
|
||||||
|
|
||||||
async def test_connection_error(
|
async def test_connection_error(
|
||||||
hass: HomeAssistant, mock_pvoutput_config_flow: MagicMock
|
hass: HomeAssistant, mock_pvoutput_config_flow: MagicMock
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test API connection error."""
|
"""Test API connection error."""
|
||||||
mock_pvoutput_config_flow.status.side_effect = PVOutputConnectionError
|
mock_pvoutput_config_flow.system.side_effect = PVOutputConnectionError
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
|
@ -123,7 +123,7 @@ async def test_connection_error(
|
||||||
assert result.get("type") == RESULT_TYPE_FORM
|
assert result.get("type") == RESULT_TYPE_FORM
|
||||||
assert result.get("errors") == {"base": "cannot_connect"}
|
assert result.get("errors") == {"base": "cannot_connect"}
|
||||||
|
|
||||||
assert len(mock_pvoutput_config_flow.status.mock_calls) == 1
|
assert len(mock_pvoutput_config_flow.system.mock_calls) == 1
|
||||||
|
|
||||||
|
|
||||||
async def test_already_configured(
|
async def test_already_configured(
|
||||||
|
@ -175,7 +175,7 @@ async def test_import_flow(
|
||||||
}
|
}
|
||||||
|
|
||||||
assert len(mock_setup_entry.mock_calls) == 1
|
assert len(mock_setup_entry.mock_calls) == 1
|
||||||
assert len(mock_pvoutput_config_flow.status.mock_calls) == 1
|
assert len(mock_pvoutput_config_flow.system.mock_calls) == 1
|
||||||
|
|
||||||
|
|
||||||
async def test_reauth_flow(
|
async def test_reauth_flow(
|
||||||
|
@ -214,7 +214,7 @@ async def test_reauth_flow(
|
||||||
}
|
}
|
||||||
|
|
||||||
assert len(mock_setup_entry.mock_calls) == 1
|
assert len(mock_setup_entry.mock_calls) == 1
|
||||||
assert len(mock_pvoutput_config_flow.status.mock_calls) == 1
|
assert len(mock_pvoutput_config_flow.system.mock_calls) == 1
|
||||||
|
|
||||||
|
|
||||||
async def test_reauth_with_authentication_error(
|
async def test_reauth_with_authentication_error(
|
||||||
|
@ -243,7 +243,7 @@ async def test_reauth_with_authentication_error(
|
||||||
assert result.get("step_id") == "reauth_confirm"
|
assert result.get("step_id") == "reauth_confirm"
|
||||||
assert "flow_id" in result
|
assert "flow_id" in result
|
||||||
|
|
||||||
mock_pvoutput_config_flow.status.side_effect = PVOutputAuthenticationError
|
mock_pvoutput_config_flow.system.side_effect = PVOutputAuthenticationError
|
||||||
result2 = await hass.config_entries.flow.async_configure(
|
result2 = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
{CONF_API_KEY: "invalid_key"},
|
{CONF_API_KEY: "invalid_key"},
|
||||||
|
@ -256,9 +256,9 @@ async def test_reauth_with_authentication_error(
|
||||||
assert "flow_id" in result2
|
assert "flow_id" in result2
|
||||||
|
|
||||||
assert len(mock_setup_entry.mock_calls) == 0
|
assert len(mock_setup_entry.mock_calls) == 0
|
||||||
assert len(mock_pvoutput_config_flow.status.mock_calls) == 1
|
assert len(mock_pvoutput_config_flow.system.mock_calls) == 1
|
||||||
|
|
||||||
mock_pvoutput_config_flow.status.side_effect = None
|
mock_pvoutput_config_flow.system.side_effect = None
|
||||||
result3 = await hass.config_entries.flow.async_configure(
|
result3 = await hass.config_entries.flow.async_configure(
|
||||||
result2["flow_id"],
|
result2["flow_id"],
|
||||||
user_input={CONF_API_KEY: "valid_key"},
|
user_input={CONF_API_KEY: "valid_key"},
|
||||||
|
@ -273,7 +273,7 @@ async def test_reauth_with_authentication_error(
|
||||||
}
|
}
|
||||||
|
|
||||||
assert len(mock_setup_entry.mock_calls) == 1
|
assert len(mock_setup_entry.mock_calls) == 1
|
||||||
assert len(mock_pvoutput_config_flow.status.mock_calls) == 2
|
assert len(mock_pvoutput_config_flow.system.mock_calls) == 2
|
||||||
|
|
||||||
|
|
||||||
async def test_reauth_api_error(
|
async def test_reauth_api_error(
|
||||||
|
@ -297,7 +297,7 @@ async def test_reauth_api_error(
|
||||||
assert result.get("step_id") == "reauth_confirm"
|
assert result.get("step_id") == "reauth_confirm"
|
||||||
assert "flow_id" in result
|
assert "flow_id" in result
|
||||||
|
|
||||||
mock_pvoutput_config_flow.status.side_effect = PVOutputConnectionError
|
mock_pvoutput_config_flow.system.side_effect = PVOutputConnectionError
|
||||||
result2 = await hass.config_entries.flow.async_configure(
|
result2 = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
{CONF_API_KEY: "some_new_key"},
|
{CONF_API_KEY: "some_new_key"},
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
"""Tests for the PVOutput integration."""
|
"""Tests for the PVOutput integration."""
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
from pvo import PVOutputAuthenticationError, PVOutputConnectionError
|
from pvo import (
|
||||||
|
PVOutputAuthenticationError,
|
||||||
|
PVOutputConnectionError,
|
||||||
|
PVOutputNoDataError,
|
||||||
|
)
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.pvoutput.const import CONF_SYSTEM_ID, DOMAIN
|
from homeassistant.components.pvoutput.const import CONF_SYSTEM_ID, DOMAIN
|
||||||
|
@ -35,13 +39,15 @@ async def test_load_unload_config_entry(
|
||||||
assert mock_config_entry.state is ConfigEntryState.NOT_LOADED
|
assert mock_config_entry.state is ConfigEntryState.NOT_LOADED
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("side_effect", [PVOutputConnectionError, PVOutputNoDataError])
|
||||||
async def test_config_entry_not_ready(
|
async def test_config_entry_not_ready(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
mock_config_entry: MockConfigEntry,
|
mock_config_entry: MockConfigEntry,
|
||||||
mock_pvoutput: MagicMock,
|
mock_pvoutput: MagicMock,
|
||||||
|
side_effect: Exception,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the PVOutput configuration entry not ready."""
|
"""Test the PVOutput configuration entry not ready."""
|
||||||
mock_pvoutput.status.side_effect = PVOutputConnectionError
|
mock_pvoutput.status.side_effect = side_effect
|
||||||
|
|
||||||
mock_config_entry.add_to_hass(hass)
|
mock_config_entry.add_to_hass(hass)
|
||||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||||
|
|
Loading…
Add table
Reference in a new issue