Remove garmin_connect integration (#52808)

Co-authored-by: Franck Nijhof <git@frenck.dev>
This commit is contained in:
Ron Klinkien 2021-07-27 21:49:49 +02:00 committed by GitHub
parent e04b2c2e35
commit 3488053648
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 0 additions and 1546 deletions

View File

@ -361,10 +361,6 @@ omit =
homeassistant/components/garages_amsterdam/__init__.py
homeassistant/components/garages_amsterdam/binary_sensor.py
homeassistant/components/garages_amsterdam/sensor.py
homeassistant/components/garmin_connect/__init__.py
homeassistant/components/garmin_connect/const.py
homeassistant/components/garmin_connect/sensor.py
homeassistant/components/garmin_connect/alarm_util.py
homeassistant/components/gc100/*
homeassistant/components/geniushub/*
homeassistant/components/generic_hygrostat/*

View File

@ -179,7 +179,6 @@ homeassistant/components/fritzbox/* @mib1185
homeassistant/components/fronius/* @nielstron
homeassistant/components/frontend/* @home-assistant/frontend
homeassistant/components/garages_amsterdam/* @klaasnicolaas
homeassistant/components/garmin_connect/* @cyberjunky
homeassistant/components/gdacs/* @exxamalte
homeassistant/components/generic_hygrostat/* @Shulyaka
homeassistant/components/geniushub/* @zxdavb

View File

@ -1,107 +0,0 @@
"""The Garmin Connect integration."""
from datetime import date
import logging
from garminconnect_ha import (
Garmin,
GarminConnectAuthenticationError,
GarminConnectConnectionError,
GarminConnectTooManyRequestsError,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.util import Throttle
from .const import DEFAULT_UPDATE_INTERVAL, DOMAIN
_LOGGER = logging.getLogger(__name__)
PLATFORMS = ["sensor"]
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up Garmin Connect from a config entry."""
username: str = entry.data[CONF_USERNAME]
password: str = entry.data[CONF_PASSWORD]
api = Garmin(username, password)
try:
await hass.async_add_executor_job(api.login)
except (
GarminConnectAuthenticationError,
GarminConnectTooManyRequestsError,
) as err:
_LOGGER.error("Error occurred during Garmin Connect login request: %s", err)
return False
except (GarminConnectConnectionError) as err:
_LOGGER.error(
"Connection error occurred during Garmin Connect login request: %s", err
)
raise ConfigEntryNotReady from err
except Exception: # pylint: disable=broad-except
_LOGGER.exception("Unknown error occurred during Garmin Connect login request")
return False
garmin_data = GarminConnectData(hass, api)
hass.data.setdefault(DOMAIN, {})
hass.data[DOMAIN][entry.entry_id] = garmin_data
hass.config_entries.async_setup_platforms(entry, PLATFORMS)
return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
"""Unload a config entry."""
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
if unload_ok:
hass.data[DOMAIN].pop(entry.entry_id)
return unload_ok
class GarminConnectData:
"""Define an object to hold sensor data."""
def __init__(self, hass, client):
"""Initialize."""
self.hass = hass
self.client = client
self.data = None
@Throttle(DEFAULT_UPDATE_INTERVAL)
async def async_update(self):
"""Update data via API wrapper."""
today = date.today()
try:
summary = await self.hass.async_add_executor_job(
self.client.get_user_summary, today.isoformat()
)
body = await self.hass.async_add_executor_job(
self.client.get_body_composition, today.isoformat()
)
self.data = {
**summary,
**body["totalAverage"],
}
self.data["nextAlarm"] = await self.hass.async_add_executor_job(
self.client.get_device_alarms
)
except (
GarminConnectAuthenticationError,
GarminConnectTooManyRequestsError,
GarminConnectConnectionError,
) as err:
_LOGGER.error(
"Error occurred during Garmin Connect update requests: %s", err
)
except Exception: # pylint: disable=broad-except
_LOGGER.exception(
"Unknown error occurred during Garmin Connect update requests"
)

View File

@ -1,50 +0,0 @@
"""Utility method for converting Garmin Connect alarms to python datetime."""
from datetime import date, datetime, timedelta
import logging
_LOGGER = logging.getLogger(__name__)
DAY_TO_NUMBER = {
"Mo": 1,
"M": 1,
"Tu": 2,
"We": 3,
"W": 3,
"Th": 4,
"Fr": 5,
"F": 5,
"Sa": 6,
"Su": 7,
}
def calculate_next_active_alarms(alarms):
"""
Calculate garmin next active alarms from settings.
Alarms are sorted by time
"""
active_alarms = []
_LOGGER.debug(alarms)
for alarm_setting in alarms:
if alarm_setting["alarmMode"] != "ON":
continue
for day in alarm_setting["alarmDays"]:
alarm_time = alarm_setting["alarmTime"]
if day == "ONCE":
midnight = datetime.combine(date.today(), datetime.min.time())
alarm = midnight + timedelta(minutes=alarm_time)
if alarm < datetime.now():
alarm += timedelta(days=1)
else:
start_of_week = datetime.combine(
date.today() - timedelta(days=datetime.today().isoweekday() % 7),
datetime.min.time(),
)
days_to_add = DAY_TO_NUMBER[day] % 7
alarm = start_of_week + timedelta(minutes=alarm_time, days=days_to_add)
if alarm < datetime.now():
alarm += timedelta(days=7)
active_alarms.append(alarm.isoformat())
return sorted(active_alarms) if active_alarms else None

View File

@ -1,72 +0,0 @@
"""Config flow for Garmin Connect integration."""
import logging
from garminconnect_ha import (
Garmin,
GarminConnectAuthenticationError,
GarminConnectConnectionError,
GarminConnectTooManyRequestsError,
)
import voluptuous as vol
from homeassistant import config_entries
from homeassistant.const import CONF_ID, CONF_PASSWORD, CONF_USERNAME
from .const import DOMAIN
_LOGGER = logging.getLogger(__name__)
class GarminConnectConfigFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle a config flow for Garmin Connect."""
VERSION = 1
async def _show_setup_form(self, errors=None):
"""Show the setup form to the user."""
return self.async_show_form(
step_id="user",
data_schema=vol.Schema(
{vol.Required(CONF_USERNAME): str, vol.Required(CONF_PASSWORD): str}
),
errors=errors or {},
)
async def async_step_user(self, user_input=None):
"""Handle the initial step."""
if user_input is None:
return await self._show_setup_form()
username = user_input[CONF_USERNAME]
password = user_input[CONF_PASSWORD]
api = Garmin(username, password)
errors = {}
try:
await self.hass.async_add_executor_job(api.login)
except GarminConnectConnectionError:
errors["base"] = "cannot_connect"
return await self._show_setup_form(errors)
except GarminConnectAuthenticationError:
errors["base"] = "invalid_auth"
return await self._show_setup_form(errors)
except GarminConnectTooManyRequestsError:
errors["base"] = "too_many_requests"
return await self._show_setup_form(errors)
except Exception: # pylint: disable=broad-except
_LOGGER.exception("Unexpected exception")
errors["base"] = "unknown"
return await self._show_setup_form(errors)
await self.async_set_unique_id(username)
self._abort_if_unique_id_configured()
return self.async_create_entry(
title=username,
data={
CONF_ID: username,
CONF_USERNAME: username,
CONF_PASSWORD: password,
},
)

View File

@ -1,355 +0,0 @@
"""Constants for the Garmin Connect integration."""
from datetime import timedelta
from homeassistant.const import (
DEVICE_CLASS_TIMESTAMP,
LENGTH_METERS,
MASS_KILOGRAMS,
PERCENTAGE,
TIME_MINUTES,
)
DOMAIN = "garmin_connect"
ATTRIBUTION = "connect.garmin.com"
DEFAULT_UPDATE_INTERVAL = timedelta(minutes=10)
GARMIN_ENTITY_LIST = {
"totalSteps": ["Total Steps", "steps", "mdi:walk", None, True],
"dailyStepGoal": ["Daily Step Goal", "steps", "mdi:walk", None, True],
"totalKilocalories": ["Total KiloCalories", "kcal", "mdi:food", None, True],
"activeKilocalories": ["Active KiloCalories", "kcal", "mdi:food", None, True],
"bmrKilocalories": ["BMR KiloCalories", "kcal", "mdi:food", None, True],
"consumedKilocalories": ["Consumed KiloCalories", "kcal", "mdi:food", None, False],
"burnedKilocalories": ["Burned KiloCalories", "kcal", "mdi:food", None, True],
"remainingKilocalories": [
"Remaining KiloCalories",
"kcal",
"mdi:food",
None,
False,
],
"netRemainingKilocalories": [
"Net Remaining KiloCalories",
"kcal",
"mdi:food",
None,
False,
],
"netCalorieGoal": ["Net Calorie Goal", "cal", "mdi:food", None, False],
"totalDistanceMeters": [
"Total Distance Mtr",
LENGTH_METERS,
"mdi:walk",
None,
True,
],
"wellnessStartTimeLocal": [
"Wellness Start Time",
None,
"mdi:clock",
DEVICE_CLASS_TIMESTAMP,
False,
],
"wellnessEndTimeLocal": [
"Wellness End Time",
None,
"mdi:clock",
DEVICE_CLASS_TIMESTAMP,
False,
],
"wellnessDescription": ["Wellness Description", "", "mdi:clock", None, False],
"wellnessDistanceMeters": [
"Wellness Distance Mtr",
LENGTH_METERS,
"mdi:walk",
None,
False,
],
"wellnessActiveKilocalories": [
"Wellness Active KiloCalories",
"kcal",
"mdi:food",
None,
False,
],
"wellnessKilocalories": ["Wellness KiloCalories", "kcal", "mdi:food", None, False],
"highlyActiveSeconds": [
"Highly Active Time",
TIME_MINUTES,
"mdi:fire",
None,
False,
],
"activeSeconds": ["Active Time", TIME_MINUTES, "mdi:fire", None, True],
"sedentarySeconds": ["Sedentary Time", TIME_MINUTES, "mdi:seat", None, True],
"sleepingSeconds": ["Sleeping Time", TIME_MINUTES, "mdi:sleep", None, True],
"measurableAwakeDuration": [
"Awake Duration",
TIME_MINUTES,
"mdi:sleep",
None,
True,
],
"measurableAsleepDuration": [
"Sleep Duration",
TIME_MINUTES,
"mdi:sleep",
None,
True,
],
"floorsAscendedInMeters": [
"Floors Ascended Mtr",
LENGTH_METERS,
"mdi:stairs",
None,
False,
],
"floorsDescendedInMeters": [
"Floors Descended Mtr",
LENGTH_METERS,
"mdi:stairs",
None,
False,
],
"floorsAscended": ["Floors Ascended", "floors", "mdi:stairs", None, True],
"floorsDescended": ["Floors Descended", "floors", "mdi:stairs", None, True],
"userFloorsAscendedGoal": [
"Floors Ascended Goal",
"floors",
"mdi:stairs",
None,
True,
],
"minHeartRate": ["Min Heart Rate", "bpm", "mdi:heart-pulse", None, True],
"maxHeartRate": ["Max Heart Rate", "bpm", "mdi:heart-pulse", None, True],
"restingHeartRate": ["Resting Heart Rate", "bpm", "mdi:heart-pulse", None, True],
"minAvgHeartRate": ["Min Avg Heart Rate", "bpm", "mdi:heart-pulse", None, False],
"maxAvgHeartRate": ["Max Avg Heart Rate", "bpm", "mdi:heart-pulse", None, False],
"abnormalHeartRateAlertsCount": [
"Abnormal HR Counts",
"",
"mdi:heart-pulse",
None,
False,
],
"lastSevenDaysAvgRestingHeartRate": [
"Last 7 Days Avg Heart Rate",
"bpm",
"mdi:heart-pulse",
None,
False,
],
"averageStressLevel": ["Avg Stress Level", "", "mdi:flash-alert", None, True],
"maxStressLevel": ["Max Stress Level", "", "mdi:flash-alert", None, True],
"stressQualifier": ["Stress Qualifier", "", "mdi:flash-alert", None, False],
"stressDuration": ["Stress Duration", TIME_MINUTES, "mdi:flash-alert", None, False],
"restStressDuration": [
"Rest Stress Duration",
TIME_MINUTES,
"mdi:flash-alert",
None,
True,
],
"activityStressDuration": [
"Activity Stress Duration",
TIME_MINUTES,
"mdi:flash-alert",
None,
True,
],
"uncategorizedStressDuration": [
"Uncat. Stress Duration",
TIME_MINUTES,
"mdi:flash-alert",
None,
True,
],
"totalStressDuration": [
"Total Stress Duration",
TIME_MINUTES,
"mdi:flash-alert",
None,
True,
],
"lowStressDuration": [
"Low Stress Duration",
TIME_MINUTES,
"mdi:flash-alert",
None,
True,
],
"mediumStressDuration": [
"Medium Stress Duration",
TIME_MINUTES,
"mdi:flash-alert",
None,
True,
],
"highStressDuration": [
"High Stress Duration",
TIME_MINUTES,
"mdi:flash-alert",
None,
True,
],
"stressPercentage": [
"Stress Percentage",
PERCENTAGE,
"mdi:flash-alert",
None,
False,
],
"restStressPercentage": [
"Rest Stress Percentage",
PERCENTAGE,
"mdi:flash-alert",
None,
False,
],
"activityStressPercentage": [
"Activity Stress Percentage",
PERCENTAGE,
"mdi:flash-alert",
None,
False,
],
"uncategorizedStressPercentage": [
"Uncat. Stress Percentage",
PERCENTAGE,
"mdi:flash-alert",
None,
False,
],
"lowStressPercentage": [
"Low Stress Percentage",
PERCENTAGE,
"mdi:flash-alert",
None,
False,
],
"mediumStressPercentage": [
"Medium Stress Percentage",
PERCENTAGE,
"mdi:flash-alert",
None,
False,
],
"highStressPercentage": [
"High Stress Percentage",
PERCENTAGE,
"mdi:flash-alert",
None,
False,
],
"moderateIntensityMinutes": [
"Moderate Intensity",
TIME_MINUTES,
"mdi:flash-alert",
None,
False,
],
"vigorousIntensityMinutes": [
"Vigorous Intensity",
TIME_MINUTES,
"mdi:run-fast",
None,
False,
],
"intensityMinutesGoal": [
"Intensity Goal",
TIME_MINUTES,
"mdi:run-fast",
None,
False,
],
"bodyBatteryChargedValue": [
"Body Battery Charged",
PERCENTAGE,
"mdi:battery-charging-100",
None,
True,
],
"bodyBatteryDrainedValue": [
"Body Battery Drained",
PERCENTAGE,
"mdi:battery-alert-variant-outline",
None,
True,
],
"bodyBatteryHighestValue": [
"Body Battery Highest",
PERCENTAGE,
"mdi:battery-heart",
None,
True,
],
"bodyBatteryLowestValue": [
"Body Battery Lowest",
PERCENTAGE,
"mdi:battery-heart-outline",
None,
True,
],
"bodyBatteryMostRecentValue": [
"Body Battery Most Recent",
PERCENTAGE,
"mdi:battery-positive",
None,
True,
],
"averageSpo2": ["Average SPO2", PERCENTAGE, "mdi:diabetes", None, True],
"lowestSpo2": ["Lowest SPO2", PERCENTAGE, "mdi:diabetes", None, True],
"latestSpo2": ["Latest SPO2", PERCENTAGE, "mdi:diabetes", None, True],
"latestSpo2ReadingTimeLocal": [
"Latest SPO2 Time",
None,
"mdi:diabetes",
DEVICE_CLASS_TIMESTAMP,
False,
],
"averageMonitoringEnvironmentAltitude": [
"Average Altitude",
PERCENTAGE,
"mdi:image-filter-hdr",
None,
False,
],
"highestRespirationValue": [
"Highest Respiration",
"brpm",
"mdi:progress-clock",
None,
False,
],
"lowestRespirationValue": [
"Lowest Respiration",
"brpm",
"mdi:progress-clock",
None,
False,
],
"latestRespirationValue": [
"Latest Respiration",
"brpm",
"mdi:progress-clock",
None,
False,
],
"latestRespirationTimeGMT": [
"Latest Respiration Update",
None,
"mdi:progress-clock",
DEVICE_CLASS_TIMESTAMP,
False,
],
"weight": ["Weight", MASS_KILOGRAMS, "mdi:weight-kilogram", None, False],
"bmi": ["BMI", "", "mdi:food", None, False],
"bodyFat": ["Body Fat", PERCENTAGE, "mdi:food", None, False],
"bodyWater": ["Body Water", PERCENTAGE, "mdi:water-percent", None, False],
"bodyMass": ["Body Mass", MASS_KILOGRAMS, "mdi:food", None, False],
"muscleMass": ["Muscle Mass", MASS_KILOGRAMS, "mdi:dumbbell", None, False],
"physiqueRating": ["Physique Rating", "", "mdi:numeric", None, False],
"visceralFat": ["Visceral Fat", "", "mdi:food", None, False],
"metabolicAge": ["Metabolic Age", "", "mdi:calendar-heart", None, False],
"nextAlarm": ["Next Alarm Time", None, "mdi:alarm", DEVICE_CLASS_TIMESTAMP, True],
}

View File

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

View File

@ -1,199 +0,0 @@
"""Platform for Garmin Connect integration."""
from __future__ import annotations
import logging
from garminconnect_ha import (
GarminConnectAuthenticationError,
GarminConnectConnectionError,
GarminConnectTooManyRequestsError,
)
from homeassistant.components.sensor import SensorEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_ATTRIBUTION, CONF_ID
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import DeviceInfo
from .alarm_util import calculate_next_active_alarms
from .const import ATTRIBUTION, DOMAIN, GARMIN_ENTITY_LIST
_LOGGER = logging.getLogger(__name__)
async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities
) -> None:
"""Set up Garmin Connect sensor based on a config entry."""
garmin_data = hass.data[DOMAIN][entry.entry_id]
unique_id = entry.data[CONF_ID]
try:
await garmin_data.async_update()
except (
GarminConnectConnectionError,
GarminConnectAuthenticationError,
GarminConnectTooManyRequestsError,
) as err:
_LOGGER.error("Error occurred during Garmin Connect Client update: %s", err)
except Exception: # pylint: disable=broad-except
_LOGGER.exception("Unknown error occurred during Garmin Connect Client update")
entities = []
for (
sensor_type,
(name, unit, icon, device_class, enabled_by_default),
) in GARMIN_ENTITY_LIST.items():
_LOGGER.debug(
"Registering entity: %s, %s, %s, %s, %s, %s",
sensor_type,
name,
unit,
icon,
device_class,
enabled_by_default,
)
entities.append(
GarminConnectSensor(
garmin_data,
unique_id,
sensor_type,
name,
unit,
icon,
device_class,
enabled_by_default,
)
)
async_add_entities(entities, True)
class GarminConnectSensor(SensorEntity):
"""Representation of a Garmin Connect Sensor."""
def __init__(
self,
data,
unique_id,
sensor_type,
name,
unit,
icon,
device_class,
enabled_default: bool = True,
):
"""Initialize."""
self._data = data
self._unique_id = unique_id
self._type = sensor_type
self._name = name
self._unit = unit
self._icon = icon
self._device_class = device_class
self._enabled_default = enabled_default
self._available = True
self._state = None
@property
def name(self):
"""Return the name of the sensor."""
return self._name
@property
def icon(self):
"""Return the icon to use in the frontend."""
return self._icon
@property
def state(self):
"""Return the state of the sensor."""
return self._state
@property
def unique_id(self) -> str:
"""Return the unique ID for this sensor."""
return f"{self._unique_id}_{self._type}"
@property
def unit_of_measurement(self):
"""Return the unit of measurement."""
return self._unit
@property
def extra_state_attributes(self):
"""Return attributes for sensor."""
if not self._data.data:
return {}
attributes = {
"source": self._data.data["source"],
"last_synced": self._data.data["lastSyncTimestampGMT"],
ATTR_ATTRIBUTION: ATTRIBUTION,
}
if self._type == "nextAlarm":
attributes["next_alarms"] = calculate_next_active_alarms(
self._data.data[self._type]
)
return attributes
@property
def device_info(self) -> DeviceInfo:
"""Return device information."""
return {
"identifiers": {(DOMAIN, self._unique_id)},
"name": "Garmin Connect",
"manufacturer": "Garmin Connect",
}
@property
def entity_registry_enabled_default(self) -> bool:
"""Return if the entity should be enabled when first added to the entity registry."""
return self._enabled_default
@property
def available(self) -> bool:
"""Return True if entity is available."""
return self._available
@property
def device_class(self):
"""Return the device class of the sensor."""
return self._device_class
async def async_update(self):
"""Update the data from Garmin Connect."""
if not self.enabled:
return
await self._data.async_update()
data = self._data.data
if not data:
_LOGGER.error("Didn't receive data from Garmin Connect")
return
if data.get(self._type) is None:
_LOGGER.debug("Entity type %s not set in fetched data", self._type)
self._available = False
return
self._available = True
if "Duration" in self._type or "Seconds" in self._type:
self._state = data[self._type] // 60
elif "Mass" in self._type or self._type == "weight":
self._state = round((data[self._type] / 1000), 2)
elif (
self._type == "bodyFat" or self._type == "bodyWater" or self._type == "bmi"
):
self._state = round(data[self._type], 2)
elif self._type == "nextAlarm":
active_alarms = calculate_next_active_alarms(data[self._type])
if active_alarms:
self._state = active_alarms[0]
else:
self._available = False
else:
self._state = data[self._type]
_LOGGER.debug(
"Entity %s set to state %s %s", self._type, self._state, self._unit
)

View File

@ -1,23 +0,0 @@
{
"config": {
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_account%]"
},
"error": {
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
"too_many_requests": "Too many requests, retry later.",
"unknown": "[%key:common::config_flow::error::unknown%]"
},
"step": {
"user": {
"data": {
"password": "[%key:common::config_flow::data::password%]",
"username": "[%key:common::config_flow::data::username%]"
},
"description": "Enter your credentials.",
"title": "Garmin Connect"
}
}
}
}

View File

@ -1,23 +0,0 @@
{
"config": {
"abort": {
"already_configured": "[%key::common::config_flow::abort::already_configured_account%]"
},
"error": {
"cannot_connect": "Ha fallat la connexi\u00f3",
"invalid_auth": "Autenticaci\u00f3 inv\u00e0lida",
"too_many_requests": "Massa sol\u00b7licituds, torna-ho a intentar m\u00e9s tard.",
"unknown": "Error inesperat"
},
"step": {
"user": {
"data": {
"password": "Contrasenya",
"username": "Nom d'usuari"
},
"description": "Introdueix les teves credencials.",
"title": "Garmin Connect"
}
}
}
}

View File

@ -1,23 +0,0 @@
{
"config": {
"abort": {
"already_configured": "\u00da\u010det je ji\u017e nastaven"
},
"error": {
"cannot_connect": "Nepoda\u0159ilo se p\u0159ipojit",
"invalid_auth": "Neplatn\u00e9 ov\u011b\u0159en\u00ed",
"too_many_requests": "P\u0159\u00edli\u0161 mnoho po\u017eadavk\u016f, opakujte to pozd\u011bji.",
"unknown": "Neo\u010dek\u00e1van\u00e1 chyba"
},
"step": {
"user": {
"data": {
"password": "Heslo",
"username": "U\u017eivatelsk\u00e9 jm\u00e9no"
},
"description": "Zadejte sv\u00e9 p\u0159ihla\u0161ovac\u00ed \u00fadaje.",
"title": "Garmin Connect"
}
}
}
}

View File

@ -1,23 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Denne konto er allerede konfigureret."
},
"error": {
"cannot_connect": "Kunne ikke oprette forbindelse - pr\u00f8v igen.",
"invalid_auth": "Ugyldig godkendelse.",
"too_many_requests": "For mange anmodninger - pr\u00f8v igen senere.",
"unknown": "Uventet fejl."
},
"step": {
"user": {
"data": {
"password": "Adgangskode",
"username": "Brugernavn"
},
"description": "Indtast dine legitimationsoplysninger.",
"title": "Garmin Connect"
}
}
}
}

View File

@ -1,23 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Konto wurde bereits konfiguriert"
},
"error": {
"cannot_connect": "Verbindung fehlgeschlagen",
"invalid_auth": "Ung\u00fcltige Authentifizierung",
"too_many_requests": "Zu viele Anfragen, versuche es sp\u00e4ter erneut.",
"unknown": "Unerwarteter Fehler"
},
"step": {
"user": {
"data": {
"password": "Passwort",
"username": "Benutzername"
},
"description": "Gib deine Zugangsdaten ein.",
"title": "Garmin Connect"
}
}
}
}

View File

@ -1,23 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Account is already configured"
},
"error": {
"cannot_connect": "Failed to connect",
"invalid_auth": "Invalid authentication",
"too_many_requests": "Too many requests, retry later.",
"unknown": "Unexpected error"
},
"step": {
"user": {
"data": {
"password": "Password",
"username": "Username"
},
"description": "Enter your credentials.",
"title": "Garmin Connect"
}
}
}
}

View File

@ -1,23 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Esta cuenta ya est\u00e1 configurada."
},
"error": {
"cannot_connect": "No se pudo conectar, intente nuevamente.",
"invalid_auth": "Autenticaci\u00f3n inv\u00e1lida",
"too_many_requests": "Demasiadas solicitudes, vuelva a intentarlo m\u00e1s tarde.",
"unknown": "Error inesperado."
},
"step": {
"user": {
"data": {
"password": "Contrase\u00f1a",
"username": "Nombre de usuario"
},
"description": "Ingrese sus credenciales.",
"title": "Garmin Connect"
}
}
}
}

View File

@ -1,23 +0,0 @@
{
"config": {
"abort": {
"already_configured": "La cuenta ya ha sido configurada"
},
"error": {
"cannot_connect": "No se pudo conectar",
"invalid_auth": "Autenticaci\u00f3n no v\u00e1lida",
"too_many_requests": "Demasiadas solicitudes, vuelva a intentarlo m\u00e1s tarde.",
"unknown": "Error inesperado"
},
"step": {
"user": {
"data": {
"password": "Contrase\u00f1a",
"username": "Usuario"
},
"description": "Introduzca sus credenciales.",
"title": "Garmin Connect"
}
}
}
}

View File

@ -1,23 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Konto on juba seadistatud"
},
"error": {
"cannot_connect": "\u00dchendamine nurjus",
"invalid_auth": "Tuvastamine nurjus",
"too_many_requests": "Liiga palju taotlusi, proovi hiljem uuesti.",
"unknown": "Tundmatu viga"
},
"step": {
"user": {
"data": {
"password": "Salas\u00f5na",
"username": "Kasutajanimi"
},
"description": "Sisesta oma mandaat.",
"title": ""
}
}
}
}

View File

@ -1,23 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Ce compte est d\u00e9j\u00e0 configur\u00e9."
},
"error": {
"cannot_connect": "Impossible de se connecter, veuillez r\u00e9essayer.",
"invalid_auth": "Authentification non valide.",
"too_many_requests": "Trop de demandes, r\u00e9essayez plus tard.",
"unknown": "Erreur inattendue."
},
"step": {
"user": {
"data": {
"password": "Mot de passe",
"username": "Nom d'utilisateur"
},
"description": "Entrez vos informations d'identification.",
"title": "Garmin Connect"
}
}
}
}

View File

@ -1,21 +0,0 @@
{
"config": {
"abort": {
"already_configured": "\u05ea\u05e6\u05d5\u05e8\u05ea \u05d4\u05d7\u05e9\u05d1\u05d5\u05df \u05db\u05d1\u05e8 \u05e0\u05e7\u05d1\u05e2\u05d4"
},
"error": {
"cannot_connect": "\u05d4\u05d4\u05ea\u05d7\u05d1\u05e8\u05d5\u05ea \u05e0\u05db\u05e9\u05dc\u05d4",
"invalid_auth": "\u05d0\u05d9\u05de\u05d5\u05ea \u05dc\u05d0 \u05d7\u05d5\u05e7\u05d9",
"too_many_requests": "\u05d1\u05e7\u05e9\u05d5\u05ea \u05e8\u05d1\u05d5\u05ea \u05de\u05d3\u05d9, \u05e0\u05d0 \u05dc\u05e0\u05e1\u05d5\u05ea \u05e9\u05e0\u05d9\u05ea \u05de\u05d0\u05d5\u05d7\u05e8 \u05d9\u05d5\u05ea\u05e8.",
"unknown": "\u05e9\u05d2\u05d9\u05d0\u05d4 \u05d1\u05dc\u05ea\u05d9 \u05e6\u05e4\u05d5\u05d9\u05d4"
},
"step": {
"user": {
"data": {
"password": "\u05e1\u05d9\u05e1\u05de\u05d4",
"username": "\u05e9\u05dd \u05de\u05e9\u05ea\u05de\u05e9"
}
}
}
}
}

View File

@ -1,23 +0,0 @@
{
"config": {
"abort": {
"already_configured": "A fi\u00f3k m\u00e1r konfigur\u00e1lva van"
},
"error": {
"cannot_connect": "Sikertelen csatlakoz\u00e1s",
"invalid_auth": "\u00c9rv\u00e9nytelen hiteles\u00edt\u00e9s",
"too_many_requests": "T\u00fal sok k\u00e9r\u00e9s, pr\u00f3b\u00e1lkozzon k\u00e9s\u0151bb \u00fajra.",
"unknown": "V\u00e1ratlan hiba t\u00f6rt\u00e9nt"
},
"step": {
"user": {
"data": {
"password": "Jelsz\u00f3",
"username": "Felhaszn\u00e1l\u00f3n\u00e9v"
},
"description": "Adja meg a hiteles\u00edt\u0151 adatait.",
"title": "Garmin Csatlakoz\u00e1s"
}
}
}
}

View File

@ -1,23 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Akun sudah dikonfigurasi"
},
"error": {
"cannot_connect": "Gagal terhubung",
"invalid_auth": "Autentikasi tidak valid",
"too_many_requests": "Terlalu banyak permintaan, coba lagi nanti.",
"unknown": "Kesalahan yang tidak diharapkan"
},
"step": {
"user": {
"data": {
"password": "Kata Sandi",
"username": "Nama Pengguna"
},
"description": "Masukkan kredensial Anda.",
"title": "Garmin Connect"
}
}
}
}

View File

@ -1,23 +0,0 @@
{
"config": {
"abort": {
"already_configured": "L'account \u00e8 gi\u00e0 configurato"
},
"error": {
"cannot_connect": "Impossibile connettersi",
"invalid_auth": "Autenticazione non valida",
"too_many_requests": "Troppe richieste, riprovare pi\u00f9 tardi.",
"unknown": "Errore imprevisto"
},
"step": {
"user": {
"data": {
"password": "Password",
"username": "Nome utente"
},
"description": "Inserisci le tue credenziali",
"title": "Garmin Connect"
}
}
}
}

View File

@ -1,23 +0,0 @@
{
"config": {
"abort": {
"already_configured": "\uacc4\uc815\uc774 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4"
},
"error": {
"cannot_connect": "\uc5f0\uacb0\ud558\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4",
"invalid_auth": "\uc778\uc99d\uc774 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4",
"too_many_requests": "\uc694\uccad\uc774 \ub108\ubb34 \ub9ce\uc2b5\ub2c8\ub2e4. \ub098\uc911\uc5d0 \ub2e4\uc2dc \uc2dc\ub3c4\ud574\uc8fc\uc138\uc694.",
"unknown": "\uc608\uc0c1\uce58 \ubabb\ud55c \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4"
},
"step": {
"user": {
"data": {
"password": "\ube44\ubc00\ubc88\ud638",
"username": "\uc0ac\uc6a9\uc790 \uc774\ub984"
},
"description": "\uc790\uaca9 \uc99d\uba85\uc744 \uc785\ub825\ud574\uc8fc\uc138\uc694",
"title": "Garmin Connect"
}
}
}
}

View File

@ -1,23 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Kont ass scho konfigur\u00e9iert"
},
"error": {
"cannot_connect": "Feeler beim verbannen",
"invalid_auth": "Ong\u00eblteg Authentifikatioun",
"too_many_requests": "Ze vill Ufroen, prob\u00e9iert sp\u00e9ider nach emol.",
"unknown": "Onerwaarte Feeler"
},
"step": {
"user": {
"data": {
"password": "Passwuert",
"username": "Benotzernumm"
},
"description": "F\u00ebllt \u00e4r Umeldungs Informatiounen aus.",
"title": "Garmin Connect"
}
}
}
}

View File

@ -1,12 +0,0 @@
{
"config": {
"step": {
"user": {
"data": {
"password": "Parole",
"username": "Lietot\u0101jv\u0101rds"
}
}
}
}
}

View File

@ -1,23 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Account is al geconfigureerd"
},
"error": {
"cannot_connect": "Kan geen verbinding maken",
"invalid_auth": "Ongeldige authenticatie",
"too_many_requests": "Te veel aanvragen, probeer het later opnieuw.",
"unknown": "Onverwachte fout"
},
"step": {
"user": {
"data": {
"password": "Wachtwoord",
"username": "Gebruikersnaam"
},
"description": "Voer uw gegevens in",
"title": "Garmin Connect"
}
}
}
}

View File

@ -1,23 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Kontoen er allerede konfigurert"
},
"error": {
"cannot_connect": "Tilkobling mislyktes",
"invalid_auth": "Ugyldig godkjenning",
"too_many_requests": "For mange foresp\u00f8rsler, pr\u00f8v p\u00e5 nytt senere.",
"unknown": "Uventet feil"
},
"step": {
"user": {
"data": {
"password": "Passord",
"username": "Brukernavn"
},
"description": "Fyll inn legitimasjonen din.",
"title": ""
}
}
}
}

View File

@ -1,23 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Konto jest ju\u017c skonfigurowane"
},
"error": {
"cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia",
"invalid_auth": "Niepoprawne uwierzytelnienie",
"too_many_requests": "Zbyt wiele \u017c\u0105da\u0144, spr\u00f3buj ponownie p\u00f3\u017aniej",
"unknown": "Nieoczekiwany b\u0142\u0105d"
},
"step": {
"user": {
"data": {
"password": "Has\u0142o",
"username": "Nazwa u\u017cytkownika"
},
"description": "Wprowad\u017a dane uwierzytelniaj\u0105ce",
"title": "Garmin Connect"
}
}
}
}

View File

@ -1,10 +0,0 @@
{
"config": {
"step": {
"user": {
"description": "Digite suas credenciais.",
"title": "Garmin Connect"
}
}
}
}

View File

@ -1,22 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Conta j\u00e1 configurada"
},
"error": {
"cannot_connect": "Falha na liga\u00e7\u00e3o",
"invalid_auth": "Autentica\u00e7\u00e3o inv\u00e1lida",
"unknown": "Erro inesperado"
},
"step": {
"user": {
"data": {
"password": "Palavra-passe",
"username": "Nome de Utilizador"
},
"description": "Introduza as suas credenciais.",
"title": "Garmin Connect"
}
}
}
}

View File

@ -1,23 +0,0 @@
{
"config": {
"abort": {
"already_configured": "\u042d\u0442\u0430 \u0443\u0447\u0451\u0442\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u0432 Home Assistant."
},
"error": {
"cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f.",
"invalid_auth": "\u041e\u0448\u0438\u0431\u043a\u0430 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438.",
"too_many_requests": "\u0421\u043b\u0438\u0448\u043a\u043e\u043c \u043c\u043d\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432, \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u0435 \u043f\u043e\u043f\u044b\u0442\u043a\u0443 \u043f\u043e\u0437\u0436\u0435.",
"unknown": "\u041d\u0435\u043f\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430."
},
"step": {
"user": {
"data": {
"password": "\u041f\u0430\u0440\u043e\u043b\u044c",
"username": "\u0418\u043c\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f"
},
"description": "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0412\u0430\u0448\u0438 \u0443\u0447\u0451\u0442\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435.",
"title": "Garmin Connect"
}
}
}
}

View File

@ -1,23 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Ta ra\u010dun je \u017ee konfiguriran."
},
"error": {
"cannot_connect": "Povezava ni uspela, poskusite znova.",
"invalid_auth": "Neveljavna avtentikacija.",
"too_many_requests": "Preve\u010d zahtev, poskusite pozneje.",
"unknown": "Nepri\u010dakovana napaka."
},
"step": {
"user": {
"data": {
"password": "Geslo",
"username": "Uporabni\u0161ko ime"
},
"description": "Vnesite svoje poverilnice.",
"title": "Garmin Connect"
}
}
}
}

View File

@ -1,23 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Det h\u00e4r kontot har redan konfigurerats."
},
"error": {
"cannot_connect": "Kunde inte ansluta, var god f\u00f6rs\u00f6k igen.",
"invalid_auth": "Ogiltig autentisering.",
"too_many_requests": "F\u00f6r m\u00e5nga f\u00f6rfr\u00e5gningar, f\u00f6rs\u00f6k igen senare.",
"unknown": "Ov\u00e4ntat fel."
},
"step": {
"user": {
"data": {
"password": "L\u00f6senord",
"username": "Anv\u00e4ndarnamn"
},
"description": "Ange dina anv\u00e4ndaruppgifter.",
"title": "Garmin Connect"
}
}
}
}

View File

@ -1,20 +0,0 @@
{
"config": {
"abort": {
"already_configured": "Hesap zaten yap\u0131land\u0131r\u0131lm\u0131\u015f"
},
"error": {
"cannot_connect": "Ba\u011flanma hatas\u0131",
"invalid_auth": "Ge\u00e7ersiz kimlik do\u011frulama",
"unknown": "Beklenmeyen hata"
},
"step": {
"user": {
"data": {
"password": "Parola",
"username": "Kullan\u0131c\u0131 Ad\u0131"
}
}
}
}
}

View File

@ -1,23 +0,0 @@
{
"config": {
"abort": {
"already_configured": "\u0426\u0435\u0439 \u043e\u0431\u043b\u0456\u043a\u043e\u0432\u0438\u0439 \u0437\u0430\u043f\u0438\u0441 \u0432\u0436\u0435 \u0434\u043e\u0434\u0430\u043d\u043e \u0432 Home Assistant."
},
"error": {
"cannot_connect": "\u041d\u0435 \u0432\u0434\u0430\u043b\u043e\u0441\u044f \u043f\u0456\u0434'\u0454\u0434\u043d\u0430\u0442\u0438\u0441\u044f",
"invalid_auth": "\u041d\u0435\u0432\u0456\u0440\u043d\u0430 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0456\u043a\u0430\u0446\u0456\u044f.",
"too_many_requests": "\u0417\u0430\u043d\u0430\u0434\u0442\u043e \u0431\u0430\u0433\u0430\u0442\u043e \u0437\u0430\u043f\u0438\u0442\u0456\u0432, \u0441\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0449\u0435 \u0440\u0430\u0437 \u043f\u0456\u0437\u043d\u0456\u0448\u0435.",
"unknown": "\u041d\u0435\u043e\u0447\u0456\u043a\u0443\u0432\u0430\u043d\u0430 \u043f\u043e\u043c\u0438\u043b\u043a\u0430"
},
"step": {
"user": {
"data": {
"password": "\u041f\u0430\u0440\u043e\u043b\u044c",
"username": "\u0406\u043c'\u044f \u043a\u043e\u0440\u0438\u0441\u0442\u0443\u0432\u0430\u0447\u0430"
},
"description": "\u0412\u0432\u0435\u0434\u0456\u0442\u044c \u0412\u0430\u0448\u0456 \u043e\u0431\u043b\u0456\u043a\u043e\u0432\u0456 \u0434\u0430\u043d\u0456.",
"title": "Garmin Connect"
}
}
}
}

View File

@ -1,11 +0,0 @@
{
"config": {
"step": {
"user": {
"data": {
"username": "\u7528\u6237\u540d"
}
}
}
}
}

View File

@ -1,23 +0,0 @@
{
"config": {
"abort": {
"already_configured": "\u5e33\u865f\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210"
},
"error": {
"cannot_connect": "\u9023\u7dda\u5931\u6557",
"invalid_auth": "\u9a57\u8b49\u78bc\u7121\u6548",
"too_many_requests": "\u8acb\u6c42\u6b21\u6578\u904e\u591a\uff0c\u8acb\u7a0d\u5f8c\u91cd\u8a66\u3002",
"unknown": "\u672a\u9810\u671f\u932f\u8aa4"
},
"step": {
"user": {
"data": {
"password": "\u5bc6\u78bc",
"username": "\u4f7f\u7528\u8005\u540d\u7a31"
},
"description": "\u8f38\u5165\u6191\u8b49\u3002",
"title": "Garmin Connect"
}
}
}
}

View File

@ -91,7 +91,6 @@ FLOWS = [
"fritzbox",
"fritzbox_callmonitor",
"garages_amsterdam",
"garmin_connect",
"gdacs",
"geofency",
"geonetnz_quakes",

View File

@ -1310,9 +1310,6 @@ ignore_errors = true
[mypy-homeassistant.components.freebox.*]
ignore_errors = true
[mypy-homeassistant.components.garmin_connect.*]
ignore_errors = true
[mypy-homeassistant.components.geniushub.*]
ignore_errors = true

View File

@ -654,9 +654,6 @@ gTTS==2.2.3
# homeassistant.components.garages_amsterdam
garages-amsterdam==2.1.1
# homeassistant.components.garmin_connect
garminconnect_ha==0.1.6
# homeassistant.components.geniushub
geniushub-client==0.6.30

View File

@ -366,9 +366,6 @@ gTTS==2.2.3
# homeassistant.components.garages_amsterdam
garages-amsterdam==2.1.1
# homeassistant.components.garmin_connect
garminconnect_ha==0.1.6
# homeassistant.components.geo_json_events
# homeassistant.components.usgs_earthquakes_feed
geojson_client==0.6

View File

@ -51,7 +51,6 @@ IGNORED_MODULES: Final[list[str]] = [
"homeassistant.components.fortios.*",
"homeassistant.components.foscam.*",
"homeassistant.components.freebox.*",
"homeassistant.components.garmin_connect.*",
"homeassistant.components.geniushub.*",
"homeassistant.components.glances.*",
"homeassistant.components.google_assistant.*",

View File

@ -1 +0,0 @@
"""Tests for the Garmin Connect component."""

View File

@ -1,112 +0,0 @@
"""Test the Garmin Connect config flow."""
from unittest.mock import patch
from garminconnect_ha import (
GarminConnectAuthenticationError,
GarminConnectConnectionError,
GarminConnectTooManyRequestsError,
)
from homeassistant import config_entries, data_entry_flow
from homeassistant.components.garmin_connect.const import DOMAIN
from homeassistant.const import CONF_ID, CONF_PASSWORD, CONF_USERNAME
from tests.common import MockConfigEntry
MOCK_CONF = {
CONF_ID: "my@email.address",
CONF_USERNAME: "my@email.address",
CONF_PASSWORD: "mypassw0rd",
}
async def test_show_form(hass):
"""Test that the form is served with no input."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == config_entries.SOURCE_USER
async def test_step_user(hass):
"""Test registering an integration and finishing flow works."""
with patch(
"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(
DOMAIN, context={"source": config_entries.SOURCE_USER}, data=MOCK_CONF
)
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert result["data"] == MOCK_CONF
async def test_connection_error(hass):
"""Test for connection error."""
with patch(
"homeassistant.components.garmin_connect.Garmin.login",
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["errors"] == {"base": "cannot_connect"}
async def test_authentication_error(hass):
"""Test for authentication error."""
with patch(
"homeassistant.components.garmin_connect.Garmin.login",
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["errors"] == {"base": "invalid_auth"}
async def test_toomanyrequest_error(hass):
"""Test for toomanyrequests error."""
with patch(
"homeassistant.components.garmin_connect.Garmin.login",
side_effect=GarminConnectTooManyRequestsError("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["errors"] == {"base": "too_many_requests"}
async def test_unknown_error(hass):
"""Test for unknown error."""
with patch(
"homeassistant.components.garmin_connect.Garmin.login",
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["errors"] == {"base": "unknown"}
async def test_abort_if_already_setup(hass):
"""Test abort if already setup."""
with patch(
"homeassistant.components.garmin_connect.config_flow.Garmin",
):
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(
DOMAIN, context={"source": "user"}, data=MOCK_CONF
)
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "already_configured"