Replace garminconnect_aio with garminconnect_ha (#51730)

* Fixed config_flow for multiple account creation

* Replaced python package to fix multiple accounts

* Replaced python package to fix multiple accounts

* Implemented config entries user

* Config entries user

* Fixed test code config flow

* Fixed patch
This commit is contained in:
Ron Klinkien 2021-06-12 10:05:27 +02:00 committed by GitHub
parent 30c53a1a13
commit f6e0165543
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 65 additions and 69 deletions

View File

@ -2,7 +2,7 @@
from datetime import date from datetime import date
import logging import logging
from garminconnect_aio import ( from garminconnect_ha import (
Garmin, Garmin,
GarminConnectAuthenticationError, GarminConnectAuthenticationError,
GarminConnectConnectionError, GarminConnectConnectionError,
@ -13,7 +13,6 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.util import Throttle from homeassistant.util import Throttle
from .const import DEFAULT_UPDATE_INTERVAL, DOMAIN from .const import DEFAULT_UPDATE_INTERVAL, DOMAIN
@ -26,14 +25,13 @@ PLATFORMS = ["sensor"]
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up Garmin Connect from a config entry.""" """Set up Garmin Connect from a config entry."""
websession = async_get_clientsession(hass)
username: str = entry.data[CONF_USERNAME] username: str = entry.data[CONF_USERNAME]
password: str = entry.data[CONF_PASSWORD] password: str = entry.data[CONF_PASSWORD]
garmin_client = Garmin(websession, username, password) api = Garmin(username, password)
try: try:
await garmin_client.login() await hass.async_add_executor_job(api.login)
except ( except (
GarminConnectAuthenticationError, GarminConnectAuthenticationError,
GarminConnectTooManyRequestsError, GarminConnectTooManyRequestsError,
@ -49,7 +47,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
_LOGGER.exception("Unknown error occurred during Garmin Connect login request") _LOGGER.exception("Unknown error occurred during Garmin Connect login request")
return False return False
garmin_data = GarminConnectData(hass, garmin_client) garmin_data = GarminConnectData(hass, api)
hass.data.setdefault(DOMAIN, {}) hass.data.setdefault(DOMAIN, {})
hass.data[DOMAIN][entry.entry_id] = garmin_data hass.data[DOMAIN][entry.entry_id] = garmin_data
@ -81,14 +79,20 @@ class GarminConnectData:
today = date.today() today = date.today()
try: try:
summary = await self.client.get_user_summary(today.isoformat()) summary = await self.hass.async_add_executor_job(
body = await self.client.get_body_composition(today.isoformat()) self.client.get_user_summary, today.isoformat()
)
body = await self.hass.async_add_executor_job(
self.client.get_body_composition, today.isoformat()
)
self.data = { self.data = {
**summary, **summary,
**body["totalAverage"], **body["totalAverage"],
} }
self.data["nextAlarm"] = await self.client.get_device_alarms() self.data["nextAlarm"] = await self.hass.async_add_executor_job(
self.client.get_device_alarms
)
except ( except (
GarminConnectAuthenticationError, GarminConnectAuthenticationError,
GarminConnectTooManyRequestsError, GarminConnectTooManyRequestsError,

View File

@ -1,7 +1,7 @@
"""Config flow for Garmin Connect integration.""" """Config flow for Garmin Connect integration."""
import logging import logging
from garminconnect_aio import ( from garminconnect_ha import (
Garmin, Garmin,
GarminConnectAuthenticationError, GarminConnectAuthenticationError,
GarminConnectConnectionError, GarminConnectConnectionError,
@ -11,7 +11,6 @@ import voluptuous as vol
from homeassistant import config_entries from homeassistant import config_entries
from homeassistant.const import CONF_ID, CONF_PASSWORD, CONF_USERNAME from homeassistant.const import CONF_ID, CONF_PASSWORD, CONF_USERNAME
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .const import DOMAIN from .const import DOMAIN
@ -38,15 +37,14 @@ class GarminConnectConfigFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
if user_input is None: if user_input is None:
return await self._show_setup_form() return await self._show_setup_form()
websession = async_get_clientsession(self.hass)
username = user_input[CONF_USERNAME] username = user_input[CONF_USERNAME]
password = user_input[CONF_PASSWORD] password = user_input[CONF_PASSWORD]
garmin_client = Garmin(websession, username, password) api = Garmin(username, password)
errors = {} errors = {}
try: try:
await garmin_client.login() await self.hass.async_add_executor_job(api.login)
except GarminConnectConnectionError: except GarminConnectConnectionError:
errors["base"] = "cannot_connect" errors["base"] = "cannot_connect"
return await self._show_setup_form(errors) return await self._show_setup_form(errors)

View File

@ -2,8 +2,8 @@
"domain": "garmin_connect", "domain": "garmin_connect",
"name": "Garmin Connect", "name": "Garmin Connect",
"documentation": "https://www.home-assistant.io/integrations/garmin_connect", "documentation": "https://www.home-assistant.io/integrations/garmin_connect",
"requirements": ["garminconnect_aio==0.1.4"], "requirements": ["garminconnect_ha==0.1.6"],
"codeowners": ["@cyberjunky"], "codeowners": ["@cyberjunky"],
"config_flow": true, "config_flow": true,
"iot_class": "cloud_polling" "iot_class": "cloud_polling"
} }

View File

@ -641,7 +641,7 @@ gTTS==2.2.2
garages-amsterdam==2.1.1 garages-amsterdam==2.1.1
# homeassistant.components.garmin_connect # homeassistant.components.garmin_connect
garminconnect_aio==0.1.4 garminconnect_ha==0.1.6
# homeassistant.components.geniushub # homeassistant.components.geniushub
geniushub-client==0.6.30 geniushub-client==0.6.30

View File

@ -347,7 +347,7 @@ gTTS==2.2.2
garages-amsterdam==2.1.1 garages-amsterdam==2.1.1
# homeassistant.components.garmin_connect # homeassistant.components.garmin_connect
garminconnect_aio==0.1.4 garminconnect_ha==0.1.6
# homeassistant.components.geo_json_events # homeassistant.components.geo_json_events
# homeassistant.components.usgs_earthquakes_feed # homeassistant.components.usgs_earthquakes_feed

View File

@ -1,12 +1,11 @@
"""Test the Garmin Connect config flow.""" """Test the Garmin Connect config flow."""
from unittest.mock import patch from unittest.mock import patch
from garminconnect_aio import ( from garminconnect_ha import (
GarminConnectAuthenticationError, GarminConnectAuthenticationError,
GarminConnectConnectionError, GarminConnectConnectionError,
GarminConnectTooManyRequestsError, GarminConnectTooManyRequestsError,
) )
import pytest
from homeassistant import config_entries, data_entry_flow from homeassistant import config_entries, data_entry_flow
from homeassistant.components.garmin_connect.const import DOMAIN from homeassistant.components.garmin_connect.const import DOMAIN
@ -21,37 +20,23 @@ MOCK_CONF = {
} }
@pytest.fixture(name="mock_garmin_connect")
def mock_garmin():
"""Mock Garmin Connect."""
with patch(
"homeassistant.components.garmin_connect.config_flow.Garmin",
) as garmin:
garmin.return_value.login.return_value = MOCK_CONF[CONF_ID]
yield garmin.return_value
async def test_show_form(hass): async def test_show_form(hass):
"""Test that the form is served with no input.""" """Test that the form is served with no input."""
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER} DOMAIN, context={"source": config_entries.SOURCE_USER}
) )
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["errors"] == {}
assert result["step_id"] == config_entries.SOURCE_USER assert result["step_id"] == config_entries.SOURCE_USER
async def test_step_user(hass): async def test_step_user(hass):
"""Test registering an integration and finishing flow works.""" """Test registering an integration and finishing flow works."""
with patch( with patch(
"homeassistant.components.garmin_connect.Garmin.login",
return_value="my@email.address",
), patch(
"homeassistant.components.garmin_connect.async_setup_entry", return_value=True "homeassistant.components.garmin_connect.async_setup_entry", return_value=True
): ), patch(
"homeassistant.components.garmin_connect.config_flow.Garmin",
) as garmin:
garmin.return_value.login.return_value = MOCK_CONF[CONF_ID]
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}, data=MOCK_CONF DOMAIN, context={"source": config_entries.SOURCE_USER}, data=MOCK_CONF
) )
@ -59,60 +44,69 @@ async def test_step_user(hass):
assert result["data"] == MOCK_CONF assert result["data"] == MOCK_CONF
async def test_connection_error(hass, mock_garmin_connect): async def test_connection_error(hass):
"""Test for connection error.""" """Test for connection error."""
mock_garmin_connect.login.side_effect = GarminConnectConnectionError("errormsg") with patch(
result = await hass.config_entries.flow.async_init( "homeassistant.components.garmin_connect.Garmin.login",
DOMAIN, context={"source": config_entries.SOURCE_USER}, data=MOCK_CONF side_effect=GarminConnectConnectionError("errormsg"),
) ):
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": "user"}, data=MOCK_CONF
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["errors"] == {"base": "cannot_connect"} assert result["errors"] == {"base": "cannot_connect"}
async def test_authentication_error(hass, mock_garmin_connect): async def test_authentication_error(hass):
"""Test for authentication error.""" """Test for authentication error."""
mock_garmin_connect.login.side_effect = GarminConnectAuthenticationError("errormsg") with patch(
result = await hass.config_entries.flow.async_init( "homeassistant.components.garmin_connect.Garmin.login",
DOMAIN, context={"source": config_entries.SOURCE_USER}, data=MOCK_CONF side_effect=GarminConnectAuthenticationError("errormsg"),
) ):
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": "user"}, data=MOCK_CONF
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["errors"] == {"base": "invalid_auth"} assert result["errors"] == {"base": "invalid_auth"}
async def test_toomanyrequest_error(hass, mock_garmin_connect): async def test_toomanyrequest_error(hass):
"""Test for toomanyrequests error.""" """Test for toomanyrequests error."""
mock_garmin_connect.login.side_effect = GarminConnectTooManyRequestsError( with patch(
"errormsg" "homeassistant.components.garmin_connect.Garmin.login",
) side_effect=GarminConnectTooManyRequestsError("errormsg"),
result = await hass.config_entries.flow.async_init( ):
DOMAIN, context={"source": config_entries.SOURCE_USER}, data=MOCK_CONF result = await hass.config_entries.flow.async_init(
) DOMAIN, context={"source": "user"}, data=MOCK_CONF
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["errors"] == {"base": "too_many_requests"} assert result["errors"] == {"base": "too_many_requests"}
async def test_unknown_error(hass, mock_garmin_connect): async def test_unknown_error(hass):
"""Test for unknown error.""" """Test for unknown error."""
mock_garmin_connect.login.side_effect = Exception with patch(
result = await hass.config_entries.flow.async_init( "homeassistant.components.garmin_connect.Garmin.login",
DOMAIN, context={"source": config_entries.SOURCE_USER}, data=MOCK_CONF side_effect=Exception,
) ):
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": "user"}, data=MOCK_CONF
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["errors"] == {"base": "unknown"} assert result["errors"] == {"base": "unknown"}
async def test_abort_if_already_setup(hass): async def test_abort_if_already_setup(hass):
"""Test abort if already setup.""" """Test abort if already setup."""
MockConfigEntry(
domain=DOMAIN, data=MOCK_CONF, unique_id=MOCK_CONF[CONF_ID]
).add_to_hass(hass)
with patch( with patch(
"homeassistant.components.garmin_connect.config_flow.Garmin", autospec=True "homeassistant.components.garmin_connect.config_flow.Garmin",
) as garmin: ):
garmin.return_value.login.return_value = MOCK_CONF[CONF_ID] entry = MockConfigEntry(
domain=DOMAIN, data=MOCK_CONF, unique_id=MOCK_CONF[CONF_ID]
)
entry.add_to_hass(hass)
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": "user"}, data=MOCK_CONF DOMAIN, context={"source": "user"}, data=MOCK_CONF
) )
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "already_configured" assert result["reason"] == "already_configured"