Skip to content

Commit e4caf37

Browse files
committed
v1.0.4: Fix config flow connection issues
## Fixed - Config flow was still using old 15s timeout and missing User-Agent headers - Added specific handling for asyncio.CancelledError during setup - Users experiencing timeouts during initial setup should now connect reliably ## Improved - Config flow now uses 30s timeout with 10s connect timeout - Added User-Agent headers to prevent WAF/CDN blocking - Better error messages for DNS, SSL, timeout issues during setup
1 parent 2a47fcc commit e4caf37

File tree

4 files changed

+85
-4
lines changed

4 files changed

+85
-4
lines changed

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,18 @@
22

33
All notable changes to Ultra Card Pro Cloud will be documented in this file.
44

5+
## [1.0.4] - 2024-12-23
6+
7+
### Fixed
8+
- **Config Flow Connection Issues**: Updated `config_flow.py` with the same connection improvements as coordinator - was still using old 15s timeout and missing User-Agent headers
9+
- **asyncio.CancelledError Handling**: Added specific handling for cancelled/interrupted requests during setup
10+
- Users experiencing timeouts during initial setup should now have more reliable connections
11+
12+
### Improved
13+
- Config flow now uses 30s timeout (was 15s) with 10s connect timeout
14+
- Added User-Agent headers to config flow requests
15+
- Better error messages for DNS, SSL, timeout, and connection issues during setup
16+
517
## [1.0.3] - 2024-12-22
618

719
### Improved

custom_components/ultra_card_pro_cloud/config_flow.py

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@
3030
RETRY_DELAY = 2 # seconds
3131
RATE_LIMIT_DELAY = 5 # seconds
3232

33+
# Connection settings (match coordinator.py)
34+
USER_AGENT = "HomeAssistant/UltraCardProCloud/1.0"
35+
REQUEST_TIMEOUT = 30 # Total timeout in seconds
36+
CONNECT_TIMEOUT = 10 # Connection establishment timeout
37+
3338
STEP_USER_DATA_SCHEMA = vol.Schema(
3439
{
3540
vol.Required(CONF_USERNAME): str,
@@ -38,6 +43,20 @@
3843
)
3944

4045

46+
def _get_timeout() -> aiohttp.ClientTimeout:
47+
"""Get standard timeout configuration."""
48+
return aiohttp.ClientTimeout(total=REQUEST_TIMEOUT, connect=CONNECT_TIMEOUT)
49+
50+
51+
def _get_headers() -> dict[str, str]:
52+
"""Get standard request headers with User-Agent."""
53+
return {
54+
"User-Agent": USER_AGENT,
55+
"Accept": "application/json",
56+
"Content-Type": "application/json",
57+
}
58+
59+
4160
async def validate_auth(
4261
hass: HomeAssistant, username: str, password: str
4362
) -> dict[str, Any]:
@@ -52,7 +71,8 @@ async def validate_auth(
5271
async with session.post(
5372
url,
5473
json={"username": username, "password": password},
55-
timeout=aiohttp.ClientTimeout(total=15),
74+
headers=_get_headers(),
75+
timeout=_get_timeout(),
5676
) as response:
5777
response_text = await response.text()
5878
_LOGGER.debug("📥 Auth response status: %s", response.status)
@@ -118,6 +138,55 @@ async def validate_auth(
118138
"display_name": data.get("user_display_name") or data.get("data", {}).get("user_display_name") or username,
119139
}
120140

141+
except aiohttp.ClientConnectorError as err:
142+
_LOGGER.error(
143+
"❌ Connection error (attempt %d/%d): %s "
144+
"(DNS or network issue - verify ultracard.io is reachable)",
145+
attempt + 1, MAX_RETRIES, err
146+
)
147+
if attempt < MAX_RETRIES - 1:
148+
await asyncio.sleep(RETRY_DELAY * (attempt + 1))
149+
continue
150+
raise CannotConnect from err
151+
except aiohttp.ClientSSLError as err:
152+
_LOGGER.error(
153+
"❌ SSL/TLS error (attempt %d/%d): %s "
154+
"(Certificate issue - may be proxy/firewall related)",
155+
attempt + 1, MAX_RETRIES, err
156+
)
157+
if attempt < MAX_RETRIES - 1:
158+
await asyncio.sleep(RETRY_DELAY * (attempt + 1))
159+
continue
160+
raise CannotConnect from err
161+
except asyncio.TimeoutError:
162+
_LOGGER.error(
163+
"❌ Connection timed out (attempt %d/%d) "
164+
"(Server did not respond within %d seconds)",
165+
attempt + 1, MAX_RETRIES, REQUEST_TIMEOUT
166+
)
167+
if attempt < MAX_RETRIES - 1:
168+
await asyncio.sleep(RETRY_DELAY * (attempt + 1))
169+
continue
170+
raise CannotConnect
171+
except asyncio.CancelledError:
172+
_LOGGER.error(
173+
"❌ Request was cancelled (attempt %d/%d) "
174+
"(Connection interrupted - may be network instability)",
175+
attempt + 1, MAX_RETRIES
176+
)
177+
if attempt < MAX_RETRIES - 1:
178+
await asyncio.sleep(RETRY_DELAY * (attempt + 1))
179+
continue
180+
raise CannotConnect
181+
except aiohttp.ServerDisconnectedError as err:
182+
_LOGGER.error(
183+
"❌ Server disconnected (attempt %d/%d): %s",
184+
attempt + 1, MAX_RETRIES, err
185+
)
186+
if attempt < MAX_RETRIES - 1:
187+
await asyncio.sleep(RETRY_DELAY * (attempt + 1))
188+
continue
189+
raise CannotConnect from err
121190
except aiohttp.ClientError as err:
122191
_LOGGER.error("❌ Connection error (attempt %d/%d): %s", attempt + 1, MAX_RETRIES, err)
123192
if attempt < MAX_RETRIES - 1:
@@ -129,7 +198,7 @@ async def validate_auth(
129198
except CannotConnect:
130199
raise
131200
except Exception as err:
132-
_LOGGER.exception("❌ Unexpected error during authentication: %s", err)
201+
_LOGGER.exception("❌ Unexpected error during authentication (%s): %s", type(err).__name__, err)
133202
if attempt < MAX_RETRIES - 1:
134203
await asyncio.sleep(RETRY_DELAY * (attempt + 1))
135204
continue

custom_components/ultra_card_pro_cloud/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@
1111
"iot_class": "cloud_polling",
1212
"issue_tracker": "https://github.com/WJDDesigns/ultra-card-pro-cloud/issues",
1313
"requirements": [],
14-
"version": "1.0.3"
14+
"version": "1.0.4"
1515
}

version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
This is the single source of truth for version information.
44
"""
55

6-
__version__ = "1.0.3"
6+
__version__ = "1.0.4"

0 commit comments

Comments
 (0)