mirror of
https://github.com/home-assistant/core.git
synced 2025-09-10 23:31:37 +02:00
Create an issue if Opower utility is no longer supported (#150315)
This commit is contained in:
@@ -2,9 +2,13 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from opower import select_utility
|
||||||
|
|
||||||
from homeassistant.const import Platform
|
from homeassistant.const import Platform
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers import issue_registry as ir
|
||||||
|
|
||||||
|
from .const import CONF_UTILITY, DOMAIN
|
||||||
from .coordinator import OpowerConfigEntry, OpowerCoordinator
|
from .coordinator import OpowerConfigEntry, OpowerCoordinator
|
||||||
|
|
||||||
PLATFORMS: list[Platform] = [Platform.SENSOR]
|
PLATFORMS: list[Platform] = [Platform.SENSOR]
|
||||||
@@ -12,6 +16,25 @@ PLATFORMS: list[Platform] = [Platform.SENSOR]
|
|||||||
|
|
||||||
async def async_setup_entry(hass: HomeAssistant, entry: OpowerConfigEntry) -> bool:
|
async def async_setup_entry(hass: HomeAssistant, entry: OpowerConfigEntry) -> bool:
|
||||||
"""Set up Opower from a config entry."""
|
"""Set up Opower from a config entry."""
|
||||||
|
utility_name = entry.data[CONF_UTILITY]
|
||||||
|
try:
|
||||||
|
select_utility(utility_name)
|
||||||
|
except ValueError:
|
||||||
|
ir.async_create_issue(
|
||||||
|
hass,
|
||||||
|
DOMAIN,
|
||||||
|
f"unsupported_utility_{entry.entry_id}",
|
||||||
|
is_fixable=True,
|
||||||
|
severity=ir.IssueSeverity.ERROR,
|
||||||
|
translation_key="unsupported_utility",
|
||||||
|
translation_placeholders={"utility": utility_name},
|
||||||
|
data={
|
||||||
|
"entry_id": entry.entry_id,
|
||||||
|
"utility": utility_name,
|
||||||
|
"title": entry.title,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
coordinator = OpowerCoordinator(hass, entry)
|
coordinator = OpowerCoordinator(hass, entry)
|
||||||
await coordinator.async_config_entry_first_refresh()
|
await coordinator.async_config_entry_first_refresh()
|
||||||
|
44
homeassistant/components/opower/repairs.py
Normal file
44
homeassistant/components/opower/repairs.py
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
"""Repairs for Opower."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from homeassistant.components.repairs import RepairsFlow
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.data_entry_flow import FlowResult
|
||||||
|
|
||||||
|
|
||||||
|
class UnsupportedUtilityFixFlow(RepairsFlow):
|
||||||
|
"""Handler for removing a configuration entry that uses an unsupported utility."""
|
||||||
|
|
||||||
|
def __init__(self, data: dict[str, str]) -> None:
|
||||||
|
"""Initialize."""
|
||||||
|
self._entry_id = data["entry_id"]
|
||||||
|
self._placeholders = data.copy()
|
||||||
|
self._placeholders.pop("entry_id")
|
||||||
|
|
||||||
|
async def async_step_init(
|
||||||
|
self, user_input: dict[str, str] | None = None
|
||||||
|
) -> FlowResult:
|
||||||
|
"""Handle the first step of a fix flow."""
|
||||||
|
return await self.async_step_confirm()
|
||||||
|
|
||||||
|
async def async_step_confirm(
|
||||||
|
self, user_input: dict[str, str] | None = None
|
||||||
|
) -> FlowResult:
|
||||||
|
"""Handle the confirm step of a fix flow."""
|
||||||
|
if user_input is not None:
|
||||||
|
await self.hass.config_entries.async_remove(self._entry_id)
|
||||||
|
return self.async_create_entry(title="", data={})
|
||||||
|
|
||||||
|
return self.async_show_form(
|
||||||
|
step_id="confirm", description_placeholders=self._placeholders
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def async_create_fix_flow(
|
||||||
|
hass: HomeAssistant, issue_id: str, data: dict[str, str] | None
|
||||||
|
) -> RepairsFlow:
|
||||||
|
"""Create flow."""
|
||||||
|
assert issue_id.startswith("unsupported_utility")
|
||||||
|
assert data
|
||||||
|
return UnsupportedUtilityFixFlow(data)
|
@@ -70,6 +70,17 @@
|
|||||||
"return_to_grid_migration": {
|
"return_to_grid_migration": {
|
||||||
"title": "Return to grid statistics for account: {utility_account_id}",
|
"title": "Return to grid statistics for account: {utility_account_id}",
|
||||||
"description": "We found negative values in your existing consumption statistics, likely because you have solar. We split those in separate return statistics for a better experience in the Energy dashboard.\n\nPlease visit the [Energy configuration page]({energy_settings}) to add the following statistics in the **Return to grid** section:\n\n{target_ids}\n\nOnce you have added them, ignore this issue."
|
"description": "We found negative values in your existing consumption statistics, likely because you have solar. We split those in separate return statistics for a better experience in the Energy dashboard.\n\nPlease visit the [Energy configuration page]({energy_settings}) to add the following statistics in the **Return to grid** section:\n\n{target_ids}\n\nOnce you have added them, ignore this issue."
|
||||||
|
},
|
||||||
|
"unsupported_utility": {
|
||||||
|
"title": "Unsupported utility: {utility}",
|
||||||
|
"fix_flow": {
|
||||||
|
"step": {
|
||||||
|
"confirm": {
|
||||||
|
"title": "[%key:component::opower::issues::unsupported_utility::title%]",
|
||||||
|
"description": "The utility `{utility}` used by entry `{title}` is no longer supported by the Opower integration. Select **Submit** to remove this integration entry now."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"entity": {
|
"entity": {
|
||||||
|
82
tests/components/opower/test_repairs.py
Normal file
82
tests/components/opower/test_repairs.py
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
"""Test the Opower repairs."""
|
||||||
|
|
||||||
|
from homeassistant.components.opower.const import DOMAIN
|
||||||
|
from homeassistant.components.recorder import Recorder
|
||||||
|
from homeassistant.components.repairs import DOMAIN as REPAIRS_DOMAIN
|
||||||
|
from homeassistant.config_entries import ConfigEntryState
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers import issue_registry as ir
|
||||||
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry
|
||||||
|
from tests.components.repairs import (
|
||||||
|
async_process_repairs_platforms,
|
||||||
|
process_repair_fix_flow,
|
||||||
|
start_repair_fix_flow,
|
||||||
|
)
|
||||||
|
from tests.typing import ClientSessionGenerator
|
||||||
|
|
||||||
|
|
||||||
|
async def test_unsupported_utility_fix_flow(
|
||||||
|
recorder_mock: Recorder,
|
||||||
|
hass: HomeAssistant,
|
||||||
|
hass_client: ClientSessionGenerator,
|
||||||
|
issue_registry: ir.IssueRegistry,
|
||||||
|
) -> None:
|
||||||
|
"""Test the unsupported utility fix flow."""
|
||||||
|
assert await async_setup_component(hass, REPAIRS_DOMAIN, {REPAIRS_DOMAIN: {}})
|
||||||
|
|
||||||
|
mock_config_entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
data={
|
||||||
|
"utility": "Unsupported Utility",
|
||||||
|
"username": "test-user",
|
||||||
|
"password": "test-password",
|
||||||
|
},
|
||||||
|
title="My Unsupported Utility",
|
||||||
|
)
|
||||||
|
mock_config_entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
# Setting up the component with an unsupported utility should fail and create an issue
|
||||||
|
assert not await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert mock_config_entry.state is ConfigEntryState.SETUP_ERROR
|
||||||
|
|
||||||
|
# Verify the issue was created correctly
|
||||||
|
issue_id = f"unsupported_utility_{mock_config_entry.entry_id}"
|
||||||
|
issue = issue_registry.async_get_issue(DOMAIN, issue_id)
|
||||||
|
assert issue is not None
|
||||||
|
assert issue.translation_key == "unsupported_utility"
|
||||||
|
assert issue.is_fixable is True
|
||||||
|
assert issue.data == {
|
||||||
|
"entry_id": mock_config_entry.entry_id,
|
||||||
|
"utility": "Unsupported Utility",
|
||||||
|
"title": "My Unsupported Utility",
|
||||||
|
}
|
||||||
|
|
||||||
|
await async_process_repairs_platforms(hass)
|
||||||
|
http_client = await hass_client()
|
||||||
|
|
||||||
|
# Start the repair flow
|
||||||
|
data = await start_repair_fix_flow(http_client, DOMAIN, issue_id)
|
||||||
|
flow_id = data["flow_id"]
|
||||||
|
|
||||||
|
# The flow should go directly to the confirm step
|
||||||
|
assert data["step_id"] == "confirm"
|
||||||
|
assert data["description_placeholders"] == {
|
||||||
|
"utility": "Unsupported Utility",
|
||||||
|
"title": "My Unsupported Utility",
|
||||||
|
}
|
||||||
|
|
||||||
|
# Submit the confirmation form
|
||||||
|
data = await process_repair_fix_flow(http_client, flow_id, json={})
|
||||||
|
|
||||||
|
# The flow should complete and create an empty entry, signaling success
|
||||||
|
assert data["type"] == "create_entry"
|
||||||
|
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
# Check that the config entry has been removed
|
||||||
|
assert hass.config_entries.async_get_entry(mock_config_entry.entry_id) is None
|
||||||
|
# Check that the issue has been resolved
|
||||||
|
assert not issue_registry.async_get_issue(DOMAIN, issue_id)
|
Reference in New Issue
Block a user