mirror of
https://github.com/home-assistant/core.git
synced 2025-07-14 08:47:10 +00:00
Require firmware version 3.1.1 for airgradient (#118744)
This commit is contained in:
parent
dd1dd4c6a3
commit
2a92f78453
@ -3,6 +3,8 @@
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from airgradient import AirGradientClient, AirGradientError, ConfigurationControl
|
from airgradient import AirGradientClient, AirGradientError, ConfigurationControl
|
||||||
|
from awesomeversion import AwesomeVersion
|
||||||
|
from mashumaro import MissingField
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components import zeroconf
|
from homeassistant.components import zeroconf
|
||||||
@ -12,6 +14,8 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
|||||||
|
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
|
|
||||||
|
MIN_VERSION = AwesomeVersion("3.1.1")
|
||||||
|
|
||||||
|
|
||||||
class AirGradientConfigFlow(ConfigFlow, domain=DOMAIN):
|
class AirGradientConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||||
"""AirGradient config flow."""
|
"""AirGradient config flow."""
|
||||||
@ -38,6 +42,9 @@ class AirGradientConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
await self.async_set_unique_id(discovery_info.properties["serialno"])
|
await self.async_set_unique_id(discovery_info.properties["serialno"])
|
||||||
self._abort_if_unique_id_configured(updates={CONF_HOST: host})
|
self._abort_if_unique_id_configured(updates={CONF_HOST: host})
|
||||||
|
|
||||||
|
if AwesomeVersion(discovery_info.properties["fw_ver"]) < MIN_VERSION:
|
||||||
|
return self.async_abort(reason="invalid_version")
|
||||||
|
|
||||||
session = async_get_clientsession(self.hass)
|
session = async_get_clientsession(self.hass)
|
||||||
self.client = AirGradientClient(host, session=session)
|
self.client = AirGradientClient(host, session=session)
|
||||||
await self.client.get_current_measures()
|
await self.client.get_current_measures()
|
||||||
@ -78,6 +85,8 @@ class AirGradientConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
current_measures = await self.client.get_current_measures()
|
current_measures = await self.client.get_current_measures()
|
||||||
except AirGradientError:
|
except AirGradientError:
|
||||||
errors["base"] = "cannot_connect"
|
errors["base"] = "cannot_connect"
|
||||||
|
except MissingField:
|
||||||
|
return self.async_abort(reason="invalid_version")
|
||||||
else:
|
else:
|
||||||
await self.async_set_unique_id(current_measures.serial_number)
|
await self.async_set_unique_id(current_measures.serial_number)
|
||||||
self._abort_if_unique_id_configured()
|
self._abort_if_unique_id_configured()
|
||||||
|
@ -15,7 +15,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"abort": {
|
"abort": {
|
||||||
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
|
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
|
||||||
|
"invalid_version": "This firmware version is unsupported. Please upgrade the firmware of the device to at least version 3.1.1."
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
||||||
|
@ -62,7 +62,7 @@ def mock_new_airgradient_client(
|
|||||||
def mock_cloud_airgradient_client(
|
def mock_cloud_airgradient_client(
|
||||||
mock_airgradient_client: AsyncMock,
|
mock_airgradient_client: AsyncMock,
|
||||||
) -> Generator[AsyncMock, None, None]:
|
) -> Generator[AsyncMock, None, None]:
|
||||||
"""Mock a new AirGradient client."""
|
"""Mock a cloud AirGradient client."""
|
||||||
mock_airgradient_client.get_config.return_value = Config.from_json(
|
mock_airgradient_client.get_config.return_value = Config.from_json(
|
||||||
load_fixture("get_config_cloud.json", DOMAIN)
|
load_fixture("get_config_cloud.json", DOMAIN)
|
||||||
)
|
)
|
||||||
|
@ -4,6 +4,7 @@ from ipaddress import ip_address
|
|||||||
from unittest.mock import AsyncMock
|
from unittest.mock import AsyncMock
|
||||||
|
|
||||||
from airgradient import AirGradientConnectionError, ConfigurationControl
|
from airgradient import AirGradientConnectionError, ConfigurationControl
|
||||||
|
from mashumaro import MissingField
|
||||||
|
|
||||||
from homeassistant.components.airgradient import DOMAIN
|
from homeassistant.components.airgradient import DOMAIN
|
||||||
from homeassistant.components.zeroconf import ZeroconfServiceInfo
|
from homeassistant.components.zeroconf import ZeroconfServiceInfo
|
||||||
@ -14,7 +15,7 @@ from homeassistant.data_entry_flow import FlowResultType
|
|||||||
|
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
ZEROCONF_DISCOVERY = ZeroconfServiceInfo(
|
OLD_ZEROCONF_DISCOVERY = ZeroconfServiceInfo(
|
||||||
ip_address=ip_address("10.0.0.131"),
|
ip_address=ip_address("10.0.0.131"),
|
||||||
ip_addresses=[ip_address("10.0.0.131")],
|
ip_addresses=[ip_address("10.0.0.131")],
|
||||||
hostname="airgradient_84fce612f5b8.local.",
|
hostname="airgradient_84fce612f5b8.local.",
|
||||||
@ -29,6 +30,21 @@ ZEROCONF_DISCOVERY = ZeroconfServiceInfo(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ZEROCONF_DISCOVERY = ZeroconfServiceInfo(
|
||||||
|
ip_address=ip_address("10.0.0.131"),
|
||||||
|
ip_addresses=[ip_address("10.0.0.131")],
|
||||||
|
hostname="airgradient_84fce612f5b8.local.",
|
||||||
|
name="airgradient_84fce612f5b8._airgradient._tcp.local.",
|
||||||
|
port=80,
|
||||||
|
type="_airgradient._tcp.local.",
|
||||||
|
properties={
|
||||||
|
"vendor": "AirGradient",
|
||||||
|
"fw_ver": "3.1.1",
|
||||||
|
"serialno": "84fce612f5b8",
|
||||||
|
"model": "I-9PSL",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def test_full_flow(
|
async def test_full_flow(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
@ -119,6 +135,34 @@ async def test_flow_errors(
|
|||||||
assert result["type"] is FlowResultType.CREATE_ENTRY
|
assert result["type"] is FlowResultType.CREATE_ENTRY
|
||||||
|
|
||||||
|
|
||||||
|
async def test_flow_old_firmware_version(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_airgradient_client: AsyncMock,
|
||||||
|
mock_setup_entry: AsyncMock,
|
||||||
|
) -> None:
|
||||||
|
"""Test flow with old firmware version."""
|
||||||
|
mock_airgradient_client.get_current_measures.side_effect = MissingField(
|
||||||
|
"", object, object
|
||||||
|
)
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN,
|
||||||
|
context={"source": SOURCE_USER},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert result["type"] is FlowResultType.FORM
|
||||||
|
assert result["step_id"] == "user"
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
{CONF_HOST: "10.0.0.131"},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert result["type"] is FlowResultType.ABORT
|
||||||
|
assert result["reason"] == "invalid_version"
|
||||||
|
|
||||||
|
|
||||||
async def test_duplicate(
|
async def test_duplicate(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
mock_airgradient_client: AsyncMock,
|
mock_airgradient_client: AsyncMock,
|
||||||
@ -197,3 +241,14 @@ async def test_zeroconf_flow_cloud_device(
|
|||||||
)
|
)
|
||||||
assert result["type"] is FlowResultType.CREATE_ENTRY
|
assert result["type"] is FlowResultType.CREATE_ENTRY
|
||||||
mock_cloud_airgradient_client.set_configuration_control.assert_not_called()
|
mock_cloud_airgradient_client.set_configuration_control.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
async def test_zeroconf_flow_abort_old_firmware(hass: HomeAssistant) -> None:
|
||||||
|
"""Test zeroconf flow aborts with old firmware."""
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN,
|
||||||
|
context={"source": SOURCE_ZEROCONF},
|
||||||
|
data=OLD_ZEROCONF_DISCOVERY,
|
||||||
|
)
|
||||||
|
assert result["type"] is FlowResultType.ABORT
|
||||||
|
assert result["reason"] == "invalid_version"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user