feat: HNAP session reuse + CM1200 timeout fix#123
Conversation
The global DEFAULT_TIMEOUT was reduced from 20s to 10s in v3.13.0, but the CM1200 over HTTPS needs more headroom. Diagnostics show read timeouts on /DocsisStatus.htm at 10s. Setting modem-specific timeout to 20s. Related to #121 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Skip redundant login when valid session credentials (uid cookie + HNAP private key) already exist. Previously, every 60s poll performed a full HNAP challenge-response login (~1440/day), triggering anti- brute-force protection on modems like the Arris S33 which reboots the device. Session reuse returns auth_performed=True to prevent _authenticate() from calling _login() on the fallback path. A separate _session_reused flag enables one stale-session retry (clear cache + fresh login) when a reused session produces zero channels. Also: S33 modem.yaml adds S33v2 model aliases and fixes attribution, CM1200 modem.yaml increases timeout to 20s for HTTPS. Related to #117 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
adapter.py maps yaml "hnap" → "hnap_session" and "basic" → "basic_http" at setup time. _has_valid_session() was checking the yaml short forms, so session reuse would never activate in production. Accept both forms. Related to #117 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The modem.yaml timeout field was intended to override the 10s default for all orchestrator requests, but _fetch_data(), _authenticate(), and discovery probing all hardcoded DEFAULT_TIMEOUT. Only the HTMLLoader respected the modem-specific value. Replace all DEFAULT_TIMEOUT references with self._timeout so modems like the CM1200 (timeout: 20) get the configured value everywhere. Related to #121 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add integration tests for v3.13.2 session reuse feature: - E2E MockModemServer tests for HNAP session reuse (4 tests) - S33v2 HAR replay tests validating HMAC-MD5 and auth flow (15 tests) - MB8600 HAR tests confirming HNAP auth detection (8 tests) - C7000v2 HAR tests for structure and content validation (6 tests) - TC4400 HAR tests for no-auth modem structure (7 tests) - S33 hnap_full_status.json fixture for MockModemServer Related to #117 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously mypy only ran on custom_components/ files during commit, missing type errors in modems/ and tests/ that CI catches. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove outdated HACS prerequisites and manual install method. Promote branch/pre-release testing via Developer Tools → Actions. Separate Installation from Setup to reduce duplication. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
HAR captures confirm the CM1200 serves status pages without any authentication. The previous basic auth config caused intermittent 401 failures because the modem rejects Authorization headers it doesn't expect. This was masked by v3.12's auth discovery fallback but became a hard failure in v3.13 which trusts modem.yaml as source of truth. Existing users must remove and re-add the integration to pick up the new auth type from modem.yaml. Related to #121 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The E2E test checks that public pages return 200 from the mock server. /index.htm was never observed in any HAR capture and has no fixture file, so listing it as public caused a test failure. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…hook The two CM1200 modem.yaml fixes (auth type basic→none, remove /index.htm) only updated the source in modems/ but were never synced to custom_components/. This caused James's config flow crash when re-adding the integration — HA was still reading basic auth config. Add a pre-commit hook that runs `make sync` whenever modems/ files change, so custom_components/ can never drift again. Also bumps har-capture dependency to 0.4.0 (raw HTTP probe support). Related to #121 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix CodeQL "redundant comparison" by comparing against stored variable - Add isinstance narrowing for HnapAuthHandler to satisfy mypy - Add assert-not-None guards for parser/adapter lookups Related to PR #123. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add CONF_PROTOCOL as a new config entry field to store the user's explicit protocol choice separately from the hostname. New entries store decomposed fields; old entries fall back to parsing the host string at runtime. When CONF_PROTOCOL is set, the orchestrator locks to that protocol with no runtime fallback. Also fix pre-existing mypy method-assign/attr-defined warnings in test_data_orchestrator.py by using mocker.patch.object instead of direct attribute assignment. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The S33/S34 modems are case-sensitive and only serve the capitalized /Cmconnectionstatus.html. The lowercase variant returned 404 on every poll cycle, wasting a request. Confirmed via HAR captures from both S33 and S33v2. Related to #117 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ences - Move har_auth_extractor.py to scripts/har/ with new har_auth_format.py and har_page_analyzer.py decomposition scripts plus README - Add tests for all three HAR scripts (tests/scripts/har/) - Rewrite ARCHITECTURE.md (1714 → 301 lines, reflect implemented code) - Rewrite TESTING.md with test architecture section, Python 3.12+ prereqs - Remove stale docs/plans/ (8 files), MODEM_LANDSCAPE.md, TECH_DEBT.md - Remove unused scripts/dev/ files (README_HOOKS.md, test_metrics.py) - Remove poc_legacy_ssl.py - Scope .gitignore har/ pattern to modems/**/har/ so scripts/har/ isn't ignored - Replace hardcoded RAW_DATA paths with generic references in docs and modem.yaml Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
har-capture v0.4.4 probe revealed the CM1200 returns 401 with WWW-Authenticate: Basic realm="Netgear" over HTTPS. Previous HAR captures were HTTP-only (no auth needed), leading to auth: none in modem.yaml which broke v3.13.0. The 401 also sets an XSRF_TOKEN cookie, but the server does not enforce it — Basic Auth alone is sufficient. Related to #121 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The CM1200 HTTPS variant returns 401 with an XSRF_TOKEN cookie that must accompany the Authorization header. Add a `challenge_cookie` flag to BasicAuthConfig that retries after the initial 401 so the session jar captures the required cookie before re-sending credentials. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
challenge_cookie was wired through the config flow but never reached the runtime DataOrchestrator → AuthHandler path. Every poll hit the CM1200's 401 challenge, got no retry, and failed. Read challenge_cookie from modem_adapter.get_static_auth_config() in __init__.py, accept it in DataOrchestrator.__init__, and forward it to AuthHandler. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
HNAP firmware can return LoginResult "LOCKUP" or "REBOOT" to signal anti-brute-force escalation. Previously these fell into the generic failure path, causing the orchestrator to retry login on the next poll and compound the problem. The HNAP builder now raises LoginLockoutError for these responses. The orchestrator catches it, sets a 3-poll backoff, and suppresses login attempts until the backoff expires. This keeps the builder stateless with respect to lockout (signal only) and the orchestrator in control of all retry policy. Also updates AI_CONTEXT.md HNAP guidance to reflect current architecture. Related to #117 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add ISP and contributor to modem.yaml, update VERIFICATION_STATUS.md and modem database README. Related to #126 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…onfig The url_token auth pipeline was silently dropping ajax_login and auth_header_data values from modem.yaml. Both handler._create_typed_config and adapter._convert_url_token_config now pass these fields through, so the SB8200 HTTPS variant correctly uses X-Requested-With on login and omits the Authorization header on data requests. Related to #81 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix CodeQL "redundant comparison" by comparing against stored variable - Add isinstance narrowing for HnapAuthHandler to satisfy mypy - Add assert-not-None guards for parser/adapter lookups Related to PR #123. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Just a follow up - been a week and still going strong no crashing! And I caught my ISP having a signal issue at 3AM this morning before my modem dropped offline! Thanks for your effort maintaining this! |
|
Thank you both! I'm trying to work through the backlog, one at a time. New v3.14 architecture is holding up pretty well. To close out issues, I just need a clean diagnostics file as proof/artifact the config is working as expected. Appreciate your support in making this a rock solid integration! |
Summary
_fetch_datapaths now useself._timeoutinstead of hardcodedDEFAULT_TIMEOUT, so modem-specific timeout config actually takes effect.Related to #117, #121.
Test plan
ruff check .passespytestfull suite passes (2599 tests)_has_valid_session(), pre-auth skip logic, stale retry conditions (12 tests)🤖 Generated with Claude Code