From 8e38f26978073f18cc0bc59d9c8b6b917cb5c6e0 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 15 May 2021 10:24:36 -0400 Subject: [PATCH] Add support for asair brand to nexia (#50504) --- homeassistant/components/nexia/__init__.py | 5 ++- homeassistant/components/nexia/config_flow.py | 14 ++++++- homeassistant/components/nexia/const.py | 5 +++ homeassistant/components/nexia/manifest.json | 4 +- homeassistant/components/nexia/strings.json | 2 +- .../components/nexia/translations/en.json | 4 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/nexia/test_config_flow.py | 40 +++++++++++++++---- tests/components/nexia/util.py | 7 ++-- 10 files changed, 64 insertions(+), 21 deletions(-) diff --git a/homeassistant/components/nexia/__init__.py b/homeassistant/components/nexia/__init__.py index da3e00b2d6a..65be22b57f1 100644 --- a/homeassistant/components/nexia/__init__.py +++ b/homeassistant/components/nexia/__init__.py @@ -3,6 +3,7 @@ from datetime import timedelta from functools import partial import logging +from nexia.const import BRAND_NEXIA from nexia.home import NexiaHome from requests.exceptions import ConnectTimeout, HTTPError @@ -13,7 +14,7 @@ from homeassistant.exceptions import ConfigEntryNotReady import homeassistant.helpers.config_validation as cv from homeassistant.helpers.update_coordinator import DataUpdateCoordinator -from .const import DOMAIN, NEXIA_DEVICE, PLATFORMS, UPDATE_COORDINATOR +from .const import CONF_BRAND, DOMAIN, NEXIA_DEVICE, PLATFORMS, UPDATE_COORDINATOR from .util import is_invalid_auth_code _LOGGER = logging.getLogger(__name__) @@ -29,6 +30,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): conf = entry.data username = conf[CONF_USERNAME] password = conf[CONF_PASSWORD] + brand = conf.get(CONF_BRAND, BRAND_NEXIA) state_file = hass.config.path(f"nexia_config_{username}.conf") @@ -40,6 +42,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): password=password, device_name=hass.config.location_name, state_file=state_file, + brand=brand, ) ) except ConnectTimeout as ex: diff --git a/homeassistant/components/nexia/config_flow.py b/homeassistant/components/nexia/config_flow.py index d9e69fd75b6..18c20a8f92a 100644 --- a/homeassistant/components/nexia/config_flow.py +++ b/homeassistant/components/nexia/config_flow.py @@ -1,6 +1,7 @@ """Config flow for Nexia integration.""" import logging +from nexia.const import BRAND_ASAIR, BRAND_NEXIA from nexia.home import NexiaHome from requests.exceptions import ConnectTimeout, HTTPError import voluptuous as vol @@ -8,12 +9,20 @@ import voluptuous as vol from homeassistant import config_entries, core, exceptions from homeassistant.const import CONF_PASSWORD, CONF_USERNAME -from .const import DOMAIN +from .const import BRAND_ASAIR_NAME, BRAND_NEXIA_NAME, CONF_BRAND, DOMAIN from .util import is_invalid_auth_code _LOGGER = logging.getLogger(__name__) -DATA_SCHEMA = vol.Schema({CONF_USERNAME: str, CONF_PASSWORD: str}) +DATA_SCHEMA = vol.Schema( + { + vol.Required(CONF_USERNAME): str, + vol.Required(CONF_PASSWORD): str, + vol.Required(CONF_BRAND, default=BRAND_NEXIA): vol.In( + {BRAND_NEXIA: BRAND_NEXIA_NAME, BRAND_ASAIR: BRAND_ASAIR_NAME} + ), + } +) async def validate_input(hass: core.HomeAssistant, data): @@ -27,6 +36,7 @@ async def validate_input(hass: core.HomeAssistant, data): nexia_home = NexiaHome( username=data[CONF_USERNAME], password=data[CONF_PASSWORD], + brand=data[CONF_BRAND], auto_login=False, auto_update=False, device_name=hass.config.location_name, diff --git a/homeassistant/components/nexia/const.py b/homeassistant/components/nexia/const.py index dbe7b71705c..d6e3e5f8008 100644 --- a/homeassistant/components/nexia/const.py +++ b/homeassistant/components/nexia/const.py @@ -7,6 +7,8 @@ ATTRIBUTION = "Data provided by mynexia.com" NOTIFICATION_ID = "nexia_notification" NOTIFICATION_TITLE = "Nexia Setup" +CONF_BRAND = "brand" + NEXIA_DEVICE = "device" NEXIA_SCAN_INTERVAL = "scan_interval" @@ -29,3 +31,6 @@ MANUFACTURER = "Trane" SIGNAL_ZONE_UPDATE = "NEXIA_CLIMATE_ZONE_UPDATE" SIGNAL_THERMOSTAT_UPDATE = "NEXIA_CLIMATE_THERMOSTAT_UPDATE" + +BRAND_NEXIA_NAME = "Nexia" +BRAND_ASAIR_NAME = "American Standard" diff --git a/homeassistant/components/nexia/manifest.json b/homeassistant/components/nexia/manifest.json index 5411723d2e2..ed1247ee9e3 100644 --- a/homeassistant/components/nexia/manifest.json +++ b/homeassistant/components/nexia/manifest.json @@ -1,7 +1,7 @@ { "domain": "nexia", - "name": "Nexia", - "requirements": ["nexia==0.9.6"], + "name": "Nexia/American Standard", + "requirements": ["nexia==0.9.7"], "codeowners": ["@bdraco"], "documentation": "https://www.home-assistant.io/integrations/nexia", "config_flow": true, diff --git a/homeassistant/components/nexia/strings.json b/homeassistant/components/nexia/strings.json index 876ea2d656f..c9bc84243da 100644 --- a/homeassistant/components/nexia/strings.json +++ b/homeassistant/components/nexia/strings.json @@ -2,8 +2,8 @@ "config": { "step": { "user": { - "title": "Connect to mynexia.com", "data": { + "brand": "Brand", "username": "[%key:common::config_flow::data::username%]", "password": "[%key:common::config_flow::data::password%]" } diff --git a/homeassistant/components/nexia/translations/en.json b/homeassistant/components/nexia/translations/en.json index fad0b8e542a..050db24e0cf 100644 --- a/homeassistant/components/nexia/translations/en.json +++ b/homeassistant/components/nexia/translations/en.json @@ -11,10 +11,10 @@ "step": { "user": { "data": { + "brand": "Brand", "password": "Password", "username": "Username" - }, - "title": "Connect to mynexia.com" + } } } } diff --git a/requirements_all.txt b/requirements_all.txt index 3f2941c3210..4ab0c5b0b3a 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1000,7 +1000,7 @@ nettigo-air-monitor==0.2.5 neurio==0.3.1 # homeassistant.components.nexia -nexia==0.9.6 +nexia==0.9.7 # homeassistant.components.nextcloud nextcloudmonitor==1.1.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 0dbb679019b..5039df65ab2 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -551,7 +551,7 @@ netdisco==2.8.3 nettigo-air-monitor==0.2.5 # homeassistant.components.nexia -nexia==0.9.6 +nexia==0.9.7 # homeassistant.components.notify_events notify-events==1.0.4 diff --git a/tests/components/nexia/test_config_flow.py b/tests/components/nexia/test_config_flow.py index b9726fdd974..2dd5c270c07 100644 --- a/tests/components/nexia/test_config_flow.py +++ b/tests/components/nexia/test_config_flow.py @@ -1,14 +1,17 @@ """Test the nexia config flow.""" from unittest.mock import MagicMock, patch +from nexia.const import BRAND_ASAIR, BRAND_NEXIA +import pytest from requests.exceptions import ConnectTimeout, HTTPError from homeassistant import config_entries, setup -from homeassistant.components.nexia.const import DOMAIN +from homeassistant.components.nexia.const import CONF_BRAND, DOMAIN from homeassistant.const import CONF_PASSWORD, CONF_USERNAME -async def test_form(hass): +@pytest.mark.parametrize("brand", [BRAND_ASAIR, BRAND_NEXIA]) +async def test_form(hass, brand): """Test we get the form.""" await setup.async_setup_component(hass, "persistent_notification", {}) result = await hass.config_entries.flow.async_init( @@ -29,13 +32,14 @@ async def test_form(hass): ) as mock_setup_entry: result2 = await hass.config_entries.flow.async_configure( result["flow_id"], - {CONF_USERNAME: "username", CONF_PASSWORD: "password"}, + {CONF_BRAND: brand, CONF_USERNAME: "username", CONF_PASSWORD: "password"}, ) await hass.async_block_till_done() assert result2["type"] == "create_entry" assert result2["title"] == "myhouse" assert result2["data"] == { + CONF_BRAND: brand, CONF_USERNAME: "username", CONF_PASSWORD: "password", } @@ -51,7 +55,11 @@ async def test_form_invalid_auth(hass): with patch("homeassistant.components.nexia.config_flow.NexiaHome.login"): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], - {CONF_USERNAME: "username", CONF_PASSWORD: "password"}, + { + CONF_BRAND: BRAND_NEXIA, + CONF_USERNAME: "username", + CONF_PASSWORD: "password", + }, ) assert result2["type"] == "form" @@ -70,7 +78,11 @@ async def test_form_cannot_connect(hass): ): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], - {CONF_USERNAME: "username", CONF_PASSWORD: "password"}, + { + CONF_BRAND: BRAND_NEXIA, + CONF_USERNAME: "username", + CONF_PASSWORD: "password", + }, ) assert result2["type"] == "form" @@ -91,7 +103,11 @@ async def test_form_invalid_auth_http_401(hass): ): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], - {CONF_USERNAME: "username", CONF_PASSWORD: "password"}, + { + CONF_BRAND: BRAND_NEXIA, + CONF_USERNAME: "username", + CONF_PASSWORD: "password", + }, ) assert result2["type"] == "form" @@ -112,7 +128,11 @@ async def test_form_cannot_connect_not_found(hass): ): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], - {CONF_USERNAME: "username", CONF_PASSWORD: "password"}, + { + CONF_BRAND: BRAND_NEXIA, + CONF_USERNAME: "username", + CONF_PASSWORD: "password", + }, ) assert result2["type"] == "form" @@ -131,7 +151,11 @@ async def test_form_broad_exception(hass): ): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], - {CONF_USERNAME: "username", CONF_PASSWORD: "password"}, + { + CONF_BRAND: BRAND_NEXIA, + CONF_USERNAME: "username", + CONF_PASSWORD: "password", + }, ) assert result2["type"] == "form" diff --git a/tests/components/nexia/util.py b/tests/components/nexia/util.py index 8e132941994..b6d5c697a18 100644 --- a/tests/components/nexia/util.py +++ b/tests/components/nexia/util.py @@ -21,17 +21,18 @@ async def async_init_integration( house_fixture = "nexia/mobile_houses_123456.json" session_fixture = "nexia/session_123456.json" sign_in_fixture = "nexia/sign_in.json" + nexia = NexiaHome(auto_login=False) with requests_mock.mock() as m, patch( "nexia.home.load_or_create_uuid", return_value=uuid.uuid4() ): - m.post(NexiaHome.API_MOBILE_SESSION_URL, text=load_fixture(session_fixture)) + m.post(nexia.API_MOBILE_SESSION_URL, text=load_fixture(session_fixture)) m.get( - NexiaHome.API_MOBILE_HOUSES_URL.format(house_id=123456), + nexia.API_MOBILE_HOUSES_URL.format(house_id=123456), text=load_fixture(house_fixture), ) m.post( - NexiaHome.API_MOBILE_ACCOUNTS_SIGN_IN_URL, + nexia.API_MOBILE_ACCOUNTS_SIGN_IN_URL, text=load_fixture(sign_in_fixture), ) entry = MockConfigEntry(