Require firmware version 3.1.1 for airgradient (#118744)

This commit is contained in:
Joost Lekkerkerker 2024-06-03 21:08:28 +02:00 committed by GitHub
parent dd1dd4c6a3
commit 2a92f78453
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 68 additions and 3 deletions

View File

@ -3,6 +3,8 @@
from typing import Any
from airgradient import AirGradientClient, AirGradientError, ConfigurationControl
from awesomeversion import AwesomeVersion
from mashumaro import MissingField
import voluptuous as vol
from homeassistant.components import zeroconf
@ -12,6 +14,8 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .const import DOMAIN
MIN_VERSION = AwesomeVersion("3.1.1")
class AirGradientConfigFlow(ConfigFlow, domain=DOMAIN):
"""AirGradient config flow."""
@ -38,6 +42,9 @@ class AirGradientConfigFlow(ConfigFlow, domain=DOMAIN):
await self.async_set_unique_id(discovery_info.properties["serialno"])
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)
self.client = AirGradientClient(host, session=session)
await self.client.get_current_measures()
@ -78,6 +85,8 @@ class AirGradientConfigFlow(ConfigFlow, domain=DOMAIN):
current_measures = await self.client.get_current_measures()
except AirGradientError:
errors["base"] = "cannot_connect"
except MissingField:
return self.async_abort(reason="invalid_version")
else:
await self.async_set_unique_id(current_measures.serial_number)
self._abort_if_unique_id_configured()

View File

@ -15,7 +15,8 @@
}
},
"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": {
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",

View File

@ -62,7 +62,7 @@ def mock_new_airgradient_client(
def mock_cloud_airgradient_client(
mock_airgradient_client: AsyncMock,
) -> Generator[AsyncMock, None, None]:
"""Mock a new AirGradient client."""
"""Mock a cloud AirGradient client."""
mock_airgradient_client.get_config.return_value = Config.from_json(
load_fixture("get_config_cloud.json", DOMAIN)
)

View File

@ -4,6 +4,7 @@ from ipaddress import ip_address
from unittest.mock import AsyncMock
from airgradient import AirGradientConnectionError, ConfigurationControl
from mashumaro import MissingField
from homeassistant.components.airgradient import DOMAIN
from homeassistant.components.zeroconf import ZeroconfServiceInfo
@ -14,7 +15,7 @@ from homeassistant.data_entry_flow import FlowResultType
from tests.common import MockConfigEntry
ZEROCONF_DISCOVERY = ZeroconfServiceInfo(
OLD_ZEROCONF_DISCOVERY = ZeroconfServiceInfo(
ip_address=ip_address("10.0.0.131"),
ip_addresses=[ip_address("10.0.0.131")],
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(
hass: HomeAssistant,
@ -119,6 +135,34 @@ async def test_flow_errors(
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(
hass: HomeAssistant,
mock_airgradient_client: AsyncMock,
@ -197,3 +241,14 @@ async def test_zeroconf_flow_cloud_device(
)
assert result["type"] is FlowResultType.CREATE_ENTRY
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"