Skip to content

Commit a875825

Browse files
jukrebsCopilot
andauthored
Add config flow exceptions to IOMeter (home-assistant#154604)
Co-authored-by: Copilot <[email protected]>
1 parent fa4eb2e commit a875825

File tree

3 files changed

+54
-12
lines changed

3 files changed

+54
-12
lines changed

homeassistant/components/iometer/config_flow.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@
22

33
from typing import Any, Final
44

5-
from iometer import IOmeterClient, IOmeterConnectionError
5+
from iometer import (
6+
IOmeterClient,
7+
IOmeterConnectionError,
8+
IOmeterNoReadingsError,
9+
IOmeterNoStatusError,
10+
)
611
import voluptuous as vol
712

813
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
@@ -34,6 +39,11 @@ async def async_step_zeroconf(
3439
client = IOmeterClient(host=host, session=session)
3540
try:
3641
status = await client.get_current_status()
42+
_ = await client.get_current_reading()
43+
except IOmeterNoStatusError:
44+
return self.async_abort(reason="no_status")
45+
except IOmeterNoReadingsError:
46+
return self.async_abort(reason="no_readings")
3747
except IOmeterConnectionError:
3848
return self.async_abort(reason="cannot_connect")
3949

@@ -70,6 +80,11 @@ async def async_step_user(
7080
client = IOmeterClient(host=self._host, session=session)
7181
try:
7282
status = await client.get_current_status()
83+
_ = await client.get_current_reading()
84+
except IOmeterNoStatusError:
85+
errors["base"] = "no_status"
86+
except IOmeterNoReadingsError:
87+
errors["base"] = "no_readings"
7388
except IOmeterConnectionError:
7489
errors["base"] = "cannot_connect"
7590
else:

homeassistant/components/iometer/strings.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
"already_in_progress": "[%key:common::config_flow::abort::already_in_progress%]"
2121
},
2222
"error": {
23+
"no_status": "No status received from the IOmeter. Check your device status in the IOmeter app",
24+
"no_readings": "No readings received from the IOmeter. Please attach the IOmeter Core to the electricity meter and wait for the first reading.",
2325
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
2426
"unknown": "[%key:common::config_flow::error::unknown%]"
2527
}

tests/components/iometer/test_config_flow.py

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
from ipaddress import ip_address
44
from unittest.mock import AsyncMock
55

6-
from iometer import IOmeterConnectionError
6+
from iometer import IOmeterConnectionError, IOmeterNoReadingsError, IOmeterNoStatusError
7+
import pytest
78

89
from homeassistant.components import zeroconf
910
from homeassistant.components.iometer.const import DOMAIN
@@ -93,29 +94,54 @@ async def test_zeroconf_flow_abort_duplicate(
9394
assert result["reason"] == "already_configured"
9495

9596

96-
async def test_zeroconf_flow_connection_error(
97+
@pytest.mark.parametrize(
98+
("method_name", "exception", "reason"),
99+
[
100+
("get_current_status", IOmeterConnectionError(), "cannot_connect"),
101+
("get_current_status", IOmeterNoStatusError(), "no_status"),
102+
("get_current_reading", IOmeterNoReadingsError(), "no_readings"),
103+
],
104+
ids=["status-connection", "status-missing", "reading-missing"],
105+
)
106+
async def test_zeroconf_flow_abort_errors(
97107
hass: HomeAssistant,
98108
mock_iometer_client: AsyncMock,
109+
method_name: str,
110+
exception: Exception,
111+
reason: str,
99112
) -> None:
100-
"""Test zeroconf flow."""
101-
mock_iometer_client.get_current_status.side_effect = IOmeterConnectionError()
113+
"""Test zeroconf flow aborts when the client raises an exception."""
114+
getattr(mock_iometer_client, method_name).side_effect = exception
115+
102116
result = await hass.config_entries.flow.async_init(
103117
DOMAIN,
104118
context={"source": SOURCE_ZEROCONF},
105119
data=ZEROCONF_DISCOVERY,
106120
)
107121
await hass.async_block_till_done()
108122
assert result["type"] is FlowResultType.ABORT
109-
assert result["reason"] == "cannot_connect"
123+
assert result["reason"] == reason
110124

111125

112-
async def test_user_flow_connection_error(
126+
@pytest.mark.parametrize(
127+
("method_name", "exception", "error_key"),
128+
[
129+
("get_current_status", IOmeterConnectionError(), "cannot_connect"),
130+
("get_current_status", IOmeterNoStatusError(), "no_status"),
131+
("get_current_reading", IOmeterNoReadingsError(), "no_readings"),
132+
],
133+
ids=["status-connection", "status-missing", "reading-missing"],
134+
)
135+
async def test_user_flow_errors(
113136
hass: HomeAssistant,
114137
mock_iometer_client: AsyncMock,
115138
mock_setup_entry: AsyncMock,
139+
method_name: str,
140+
exception: Exception,
141+
error_key: str,
116142
) -> None:
117-
"""Test flow error."""
118-
mock_iometer_client.get_current_status.side_effect = IOmeterConnectionError()
143+
"""Test user flow returns errors for client exceptions."""
144+
getattr(mock_iometer_client, method_name).side_effect = exception
119145

120146
result = await hass.config_entries.flow.async_init(
121147
DOMAIN,
@@ -130,11 +156,10 @@ async def test_user_flow_connection_error(
130156
{CONF_HOST: IP_ADDRESS},
131157
)
132158
await hass.async_block_till_done()
133-
134159
assert result["type"] is FlowResultType.FORM
135-
assert result["errors"] == {"base": "cannot_connect"}
160+
assert result["errors"] == {"base": error_key}
136161

137-
mock_iometer_client.get_current_status.side_effect = None
162+
getattr(mock_iometer_client, method_name).side_effect = None
138163

139164
result = await hass.config_entries.flow.async_configure(
140165
result["flow_id"],

0 commit comments

Comments
 (0)