Skip to content

Update to use Kumo Cloud v3 API only#222

Merged
dlarrick merged 6 commits into
masterfrom
dcl_no_v3
May 25, 2026
Merged

Update to use Kumo Cloud v3 API only#222
dlarrick merged 6 commits into
masterfrom
dcl_no_v3

Conversation

@dlarrick

Copy link
Copy Markdown
Owner

Add basic unit tests
Add pre-commit with ruff formatting
Expand list of MACs to probe
Add Home Assistant diagnostics capability

Add basic unit tests
Add pre-commit with ruff formatting
Expand list of MACs to probe
Add Home Assistant diagnostics capability

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the Kumo Home Assistant custom component to rely on the Kumo Cloud v3 API path (via newer pykumo), adds DHCP-based discovery enhancements, and introduces initial developer tooling/tests plus Home Assistant diagnostics support.

Changes:

  • Bump pykumo minimum version and remove v2 fallback behavior in setup/validation paths.
  • Add DHCP discovery MAC prefixes and implement DHCP flow behavior (including storing candidate IPs and scheduling reloads when already configured).
  • Add initial config-flow unit tests, diagnostics support, and ruff pre-commit hooks.

Reviewed changes

Copilot reviewed 13 out of 17 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/test_config_flow.py Adds basic unit tests for user config flow and DHCP discovery behavior.
README.md Updates documentation for prefer_cache, DHCP discovery, and moves historical note to a dedicated section.
custom_components/kumo/manifest.json Bumps pykumo requirement and expands DHCP MAC prefix matching.
custom_components/kumo/diagnostics.py Adds Home Assistant diagnostics endpoints for config entries and devices.
custom_components/kumo/config_flow.py Simplifies validation to v3-only and updates DHCP discovery flow behavior.
custom_components/kumo/__init__.py Refactors entry setup to a single try_setup path using cache + DHCP candidate IPs.
.pre-commit-config.yaml Adds ruff linting/formatting hooks.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread custom_components/kumo/config_flow.py
Comment thread custom_components/kumo/__init__.py Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 22 changed files in this pull request and generated 5 comments.

Comment thread tests/conftest.py Outdated


@pytest.fixture(autouse=True)
def enable_custom_integrations(enable_custom_integrations):
Comment thread .github/workflows/pytest.yml Outdated
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install .
Comment on lines 94 to +102
try:
setup_success = await hass.async_add_executor_job(
account.try_setup_v3_only, candidate_ips or {}
account.try_setup, candidate_ips, prefer_cache
)
except (ConnectionError, OSError) as err:
_LOGGER.warning("V3 setup failed due to network error, will fall back to V2: %s", err)
return None
_LOGGER.warning("Kumo setup failed due to network error: %s", err)
return False
except (json.JSONDecodeError, binascii.Error, ValueError) as err:
_LOGGER.error("Kumo setup failed due to malformed cached data: %s", err)
Comment thread tests/test_config_flow.py Outdated
"""Test DHCP discovery when already configured."""
from homeassistant.helpers.service_info.dhcp import DhcpServiceInfo
from pytest_homeassistant_custom_component.common import MockConfigEntry
from unittest.mock import patch
Comment thread tests/test_scenarios.py Outdated
Comment on lines +1 to +20
import pytest
from unittest.mock import patch
from homeassistant.core import HomeAssistant
from custom_components.kumo.const import DOMAIN
from pytest_homeassistant_custom_component.common import MockConfigEntry


@pytest.fixture
async def kumo_setup(hass):
"""Fixture to set up the kumo integration."""
entry = MockConfigEntry(
domain=DOMAIN, data={"username": "user", "password": "pass"}
)
entry.add_to_hass(hass)
with patch("custom_components.kumo.async_setup_entry", return_value=True):
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
return entry


Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 22 changed files in this pull request and generated 2 comments.

Comment on lines +83 to +103
# Load cached config if available
cached_dict = await hass.async_add_executor_job(
load_json, hass.config.path(KUMO_CONFIG_CACHE)
)
if cached_dict and isinstance(cached_dict, list) and len(cached_dict) >= 3:
account = pykumo.KumoCloudAccount(username, password, kumo_dict=cached_dict)
else:
account = pykumo.KumoCloudAccount(username, password)
if not isinstance(cached_dict, list) or len(cached_dict) < 3:
cached_dict = None

# Initialize account and try setup
account = pykumo.KumoCloudAccount(username, password, kumo_dict=cached_dict)
candidate_ips = hass.data.get(DHCP_DISCOVERED_KEY, {})

try:
setup_success = await hass.async_add_executor_job(
account.try_setup_v3_only, candidate_ips or {}
account.try_setup, candidate_ips, prefer_cache
)
except (ConnectionError, OSError) as err:
_LOGGER.warning("V3 setup failed due to network error, will fall back to V2: %s", err)
return None
_LOGGER.warning("Kumo setup failed due to network error: %s", err)
return False
except (json.JSONDecodeError, binascii.Error, ValueError) as err:
_LOGGER.error("Kumo setup failed due to malformed cached data: %s", err)
return False
Comment thread tests/test_scenarios.py
Comment on lines +1 to +62
from unittest.mock import patch
from homeassistant.core import HomeAssistant
from custom_components.kumo.const import DOMAIN
from pytest_homeassistant_custom_component.common import MockConfigEntry


async def test_scenario_1_cached_info_fine(hass: HomeAssistant):
"""Cached info is fine. Units reachable."""
with (
patch("pykumo.KumoCloudAccount.try_setup", return_value=True),
patch(
"pykumo.KumoCloudAccount.get_raw_json",
return_value=[
{},
{},
{"children": [{"zoneTable": {"S1": {"address": "1.1.1.1"}}}]},
],
),
):
entry = MockConfigEntry(domain=DOMAIN, data={"username": "u", "password": "p"})
entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(entry.entry_id)


async def test_scenario_2_cached_info_unreachable(hass: HomeAssistant):
"""Cached info fine, some unreachable."""
with patch("pykumo.KumoCloudAccount.try_setup", return_value=True):
entry = MockConfigEntry(domain=DOMAIN, data={"username": "u", "password": "p"})
entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(entry.entry_id)


async def test_scenario_3_stale_ip_new_discovery(hass: HomeAssistant):
"""Stale IP in cache, new address in discovery."""
with patch("pykumo.KumoCloudAccount.try_setup", return_value=True):
entry = MockConfigEntry(domain=DOMAIN, data={"username": "u", "password": "p"})
entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(entry.entry_id)


async def test_scenario_4_new_unit_in_discovery(hass: HomeAssistant):
"""New unit in discovery."""
with patch("pykumo.KumoCloudAccount.try_setup", return_value=True):
entry = MockConfigEntry(domain=DOMAIN, data={"username": "u", "password": "p"})
entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(entry.entry_id)


async def test_scenario_5_new_installation_all_discovered(hass: HomeAssistant):
"""New installation, all in discovery."""
with patch("pykumo.KumoCloudAccount.try_setup", return_value=True):
entry = MockConfigEntry(domain=DOMAIN, data={"username": "u", "password": "p"})
entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(entry.entry_id)


async def test_scenario_6_new_installation_missing_discovery(hass: HomeAssistant):
"""New installation, missing discovery."""
with patch("pykumo.KumoCloudAccount.try_setup", return_value=True):
entry = MockConfigEntry(domain=DOMAIN, data={"username": "u", "password": "p"})
entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(entry.entry_id)
@dlarrick dlarrick merged commit f5eb7af into master May 25, 2026
3 checks passed
@dlarrick dlarrick deleted the dcl_no_v3 branch May 25, 2026 15:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants