Add support for asair brand to nexia (#50504)

This commit is contained in:
J. Nick Koston 2021-05-15 10:24:36 -04:00 committed by GitHub
parent bdeeb54d2d
commit 8e38f26978
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 64 additions and 21 deletions

View File

@ -3,6 +3,7 @@ from datetime import timedelta
from functools import partial from functools import partial
import logging import logging
from nexia.const import BRAND_NEXIA
from nexia.home import NexiaHome from nexia.home import NexiaHome
from requests.exceptions import ConnectTimeout, HTTPError from requests.exceptions import ConnectTimeout, HTTPError
@ -13,7 +14,7 @@ from homeassistant.exceptions import ConfigEntryNotReady
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator 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 from .util import is_invalid_auth_code
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -29,6 +30,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
conf = entry.data conf = entry.data
username = conf[CONF_USERNAME] username = conf[CONF_USERNAME]
password = conf[CONF_PASSWORD] password = conf[CONF_PASSWORD]
brand = conf.get(CONF_BRAND, BRAND_NEXIA)
state_file = hass.config.path(f"nexia_config_{username}.conf") 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, password=password,
device_name=hass.config.location_name, device_name=hass.config.location_name,
state_file=state_file, state_file=state_file,
brand=brand,
) )
) )
except ConnectTimeout as ex: except ConnectTimeout as ex:

View File

@ -1,6 +1,7 @@
"""Config flow for Nexia integration.""" """Config flow for Nexia integration."""
import logging import logging
from nexia.const import BRAND_ASAIR, BRAND_NEXIA
from nexia.home import NexiaHome from nexia.home import NexiaHome
from requests.exceptions import ConnectTimeout, HTTPError from requests.exceptions import ConnectTimeout, HTTPError
import voluptuous as vol import voluptuous as vol
@ -8,12 +9,20 @@ import voluptuous as vol
from homeassistant import config_entries, core, exceptions from homeassistant import config_entries, core, exceptions
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME 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 from .util import is_invalid_auth_code
_LOGGER = logging.getLogger(__name__) _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): async def validate_input(hass: core.HomeAssistant, data):
@ -27,6 +36,7 @@ async def validate_input(hass: core.HomeAssistant, data):
nexia_home = NexiaHome( nexia_home = NexiaHome(
username=data[CONF_USERNAME], username=data[CONF_USERNAME],
password=data[CONF_PASSWORD], password=data[CONF_PASSWORD],
brand=data[CONF_BRAND],
auto_login=False, auto_login=False,
auto_update=False, auto_update=False,
device_name=hass.config.location_name, device_name=hass.config.location_name,

View File

@ -7,6 +7,8 @@ ATTRIBUTION = "Data provided by mynexia.com"
NOTIFICATION_ID = "nexia_notification" NOTIFICATION_ID = "nexia_notification"
NOTIFICATION_TITLE = "Nexia Setup" NOTIFICATION_TITLE = "Nexia Setup"
CONF_BRAND = "brand"
NEXIA_DEVICE = "device" NEXIA_DEVICE = "device"
NEXIA_SCAN_INTERVAL = "scan_interval" NEXIA_SCAN_INTERVAL = "scan_interval"
@ -29,3 +31,6 @@ MANUFACTURER = "Trane"
SIGNAL_ZONE_UPDATE = "NEXIA_CLIMATE_ZONE_UPDATE" SIGNAL_ZONE_UPDATE = "NEXIA_CLIMATE_ZONE_UPDATE"
SIGNAL_THERMOSTAT_UPDATE = "NEXIA_CLIMATE_THERMOSTAT_UPDATE" SIGNAL_THERMOSTAT_UPDATE = "NEXIA_CLIMATE_THERMOSTAT_UPDATE"
BRAND_NEXIA_NAME = "Nexia"
BRAND_ASAIR_NAME = "American Standard"

View File

@ -1,7 +1,7 @@
{ {
"domain": "nexia", "domain": "nexia",
"name": "Nexia", "name": "Nexia/American Standard",
"requirements": ["nexia==0.9.6"], "requirements": ["nexia==0.9.7"],
"codeowners": ["@bdraco"], "codeowners": ["@bdraco"],
"documentation": "https://www.home-assistant.io/integrations/nexia", "documentation": "https://www.home-assistant.io/integrations/nexia",
"config_flow": true, "config_flow": true,

View File

@ -2,8 +2,8 @@
"config": { "config": {
"step": { "step": {
"user": { "user": {
"title": "Connect to mynexia.com",
"data": { "data": {
"brand": "Brand",
"username": "[%key:common::config_flow::data::username%]", "username": "[%key:common::config_flow::data::username%]",
"password": "[%key:common::config_flow::data::password%]" "password": "[%key:common::config_flow::data::password%]"
} }

View File

@ -11,10 +11,10 @@
"step": { "step": {
"user": { "user": {
"data": { "data": {
"brand": "Brand",
"password": "Password", "password": "Password",
"username": "Username" "username": "Username"
}, }
"title": "Connect to mynexia.com"
} }
} }
} }

View File

@ -1000,7 +1000,7 @@ nettigo-air-monitor==0.2.5
neurio==0.3.1 neurio==0.3.1
# homeassistant.components.nexia # homeassistant.components.nexia
nexia==0.9.6 nexia==0.9.7
# homeassistant.components.nextcloud # homeassistant.components.nextcloud
nextcloudmonitor==1.1.0 nextcloudmonitor==1.1.0

View File

@ -551,7 +551,7 @@ netdisco==2.8.3
nettigo-air-monitor==0.2.5 nettigo-air-monitor==0.2.5
# homeassistant.components.nexia # homeassistant.components.nexia
nexia==0.9.6 nexia==0.9.7
# homeassistant.components.notify_events # homeassistant.components.notify_events
notify-events==1.0.4 notify-events==1.0.4

View File

@ -1,14 +1,17 @@
"""Test the nexia config flow.""" """Test the nexia config flow."""
from unittest.mock import MagicMock, patch from unittest.mock import MagicMock, patch
from nexia.const import BRAND_ASAIR, BRAND_NEXIA
import pytest
from requests.exceptions import ConnectTimeout, HTTPError from requests.exceptions import ConnectTimeout, HTTPError
from homeassistant import config_entries, setup 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 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.""" """Test we get the form."""
await setup.async_setup_component(hass, "persistent_notification", {}) await setup.async_setup_component(hass, "persistent_notification", {})
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
@ -29,13 +32,14 @@ async def test_form(hass):
) as mock_setup_entry: ) as mock_setup_entry:
result2 = await hass.config_entries.flow.async_configure( result2 = await hass.config_entries.flow.async_configure(
result["flow_id"], result["flow_id"],
{CONF_USERNAME: "username", CONF_PASSWORD: "password"}, {CONF_BRAND: brand, CONF_USERNAME: "username", CONF_PASSWORD: "password"},
) )
await hass.async_block_till_done() await hass.async_block_till_done()
assert result2["type"] == "create_entry" assert result2["type"] == "create_entry"
assert result2["title"] == "myhouse" assert result2["title"] == "myhouse"
assert result2["data"] == { assert result2["data"] == {
CONF_BRAND: brand,
CONF_USERNAME: "username", CONF_USERNAME: "username",
CONF_PASSWORD: "password", CONF_PASSWORD: "password",
} }
@ -51,7 +55,11 @@ async def test_form_invalid_auth(hass):
with patch("homeassistant.components.nexia.config_flow.NexiaHome.login"): with patch("homeassistant.components.nexia.config_flow.NexiaHome.login"):
result2 = await hass.config_entries.flow.async_configure( result2 = await hass.config_entries.flow.async_configure(
result["flow_id"], result["flow_id"],
{CONF_USERNAME: "username", CONF_PASSWORD: "password"}, {
CONF_BRAND: BRAND_NEXIA,
CONF_USERNAME: "username",
CONF_PASSWORD: "password",
},
) )
assert result2["type"] == "form" assert result2["type"] == "form"
@ -70,7 +78,11 @@ async def test_form_cannot_connect(hass):
): ):
result2 = await hass.config_entries.flow.async_configure( result2 = await hass.config_entries.flow.async_configure(
result["flow_id"], result["flow_id"],
{CONF_USERNAME: "username", CONF_PASSWORD: "password"}, {
CONF_BRAND: BRAND_NEXIA,
CONF_USERNAME: "username",
CONF_PASSWORD: "password",
},
) )
assert result2["type"] == "form" 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( result2 = await hass.config_entries.flow.async_configure(
result["flow_id"], result["flow_id"],
{CONF_USERNAME: "username", CONF_PASSWORD: "password"}, {
CONF_BRAND: BRAND_NEXIA,
CONF_USERNAME: "username",
CONF_PASSWORD: "password",
},
) )
assert result2["type"] == "form" 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( result2 = await hass.config_entries.flow.async_configure(
result["flow_id"], result["flow_id"],
{CONF_USERNAME: "username", CONF_PASSWORD: "password"}, {
CONF_BRAND: BRAND_NEXIA,
CONF_USERNAME: "username",
CONF_PASSWORD: "password",
},
) )
assert result2["type"] == "form" assert result2["type"] == "form"
@ -131,7 +151,11 @@ async def test_form_broad_exception(hass):
): ):
result2 = await hass.config_entries.flow.async_configure( result2 = await hass.config_entries.flow.async_configure(
result["flow_id"], result["flow_id"],
{CONF_USERNAME: "username", CONF_PASSWORD: "password"}, {
CONF_BRAND: BRAND_NEXIA,
CONF_USERNAME: "username",
CONF_PASSWORD: "password",
},
) )
assert result2["type"] == "form" assert result2["type"] == "form"

View File

@ -21,17 +21,18 @@ async def async_init_integration(
house_fixture = "nexia/mobile_houses_123456.json" house_fixture = "nexia/mobile_houses_123456.json"
session_fixture = "nexia/session_123456.json" session_fixture = "nexia/session_123456.json"
sign_in_fixture = "nexia/sign_in.json" sign_in_fixture = "nexia/sign_in.json"
nexia = NexiaHome(auto_login=False)
with requests_mock.mock() as m, patch( with requests_mock.mock() as m, patch(
"nexia.home.load_or_create_uuid", return_value=uuid.uuid4() "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( 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), text=load_fixture(house_fixture),
) )
m.post( m.post(
NexiaHome.API_MOBILE_ACCOUNTS_SIGN_IN_URL, nexia.API_MOBILE_ACCOUNTS_SIGN_IN_URL,
text=load_fixture(sign_in_fixture), text=load_fixture(sign_in_fixture),
) )
entry = MockConfigEntry( entry = MockConfigEntry(