From eda68f127c93446598d0927115c6b2e265d44959 Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Mon, 28 Sep 2020 16:07:17 +0200 Subject: [PATCH] Add rpi_power during onboarding on RPi (#40076) --- .../components/onboarding/manifest.json | 13 ++- homeassistant/components/onboarding/views.py | 8 ++ .../components/rpi_power/config_flow.py | 33 ++++-- tests/components/onboarding/test_views.py | 100 ++++++++++++++++++ .../components/rpi_power/test_config_flow.py | 25 ++++- 5 files changed, 168 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/onboarding/manifest.json b/homeassistant/components/onboarding/manifest.json index 81e88e99edb..e2fb8e084b8 100644 --- a/homeassistant/components/onboarding/manifest.json +++ b/homeassistant/components/onboarding/manifest.json @@ -2,7 +2,16 @@ "domain": "onboarding", "name": "Home Assistant Onboarding", "documentation": "https://www.home-assistant.io/integrations/onboarding", - "dependencies": ["auth", "http", "person"], - "codeowners": ["@home-assistant/core"], + "after_dependencies": [ + "hassio" + ], + "dependencies": [ + "auth", + "http", + "person" + ], + "codeowners": [ + "@home-assistant/core" + ], "quality_scale": "internal" } diff --git a/homeassistant/components/onboarding/views.py b/homeassistant/components/onboarding/views.py index a2a4fb15fd7..0faf099b9bf 100644 --- a/homeassistant/components/onboarding/views.py +++ b/homeassistant/components/onboarding/views.py @@ -159,6 +159,14 @@ class CoreConfigOnboardingView(_BaseOnboardingView): "met", context={"source": "onboarding"} ) + if ( + hass.components.hassio.is_hassio() + and "raspberrypi" in hass.components.hassio.get_core_info()["machine"] + ): + await hass.config_entries.flow.async_init( + "rpi_power", context={"source": "onboarding"} + ) + return self.json({}) diff --git a/homeassistant/components/rpi_power/config_flow.py b/homeassistant/components/rpi_power/config_flow.py index 6112bddb7d5..9924ebf0440 100644 --- a/homeassistant/components/rpi_power/config_flow.py +++ b/homeassistant/components/rpi_power/config_flow.py @@ -1,9 +1,11 @@ """Config flow for Raspberry Pi Power Supply Checker.""" +from typing import Any, Dict, Optional + from rpi_bad_power import new_under_voltage from homeassistant import config_entries from homeassistant.core import HomeAssistant -from homeassistant.helpers import config_entry_flow +from homeassistant.helpers.config_entry_flow import DiscoveryFlowHandler from .const import DOMAIN @@ -14,9 +16,26 @@ async def _async_supported(hass: HomeAssistant) -> bool: return under_voltage is not None -config_entry_flow.register_discovery_flow( - DOMAIN, - "Raspberry Pi Power Supply Checker", - _async_supported, - config_entries.CONN_CLASS_LOCAL_POLL, -) +class RPiPowerFlow(DiscoveryFlowHandler, domain=DOMAIN): + """Discovery flow handler.""" + + VERSION = 1 + + def __init__(self) -> None: + """Set up config flow.""" + super().__init__( + DOMAIN, + "Raspberry Pi Power Supply Checker", + _async_supported, + config_entries.CONN_CLASS_LOCAL_POLL, + ) + + async def async_step_onboarding( + self, data: Optional[Dict[str, Any]] = None + ) -> Dict[str, Any]: + """Handle a flow initialized by onboarding.""" + has_devices = await self._discovery_function(self.hass) + + if not has_devices: + return self.async_abort(reason="no_devices_found") + return self.async_create_entry(title=self._title, data={}) diff --git a/tests/components/onboarding/test_views.py b/tests/components/onboarding/test_views.py index 0d425642622..a1b857a52ce 100644 --- a/tests/components/onboarding/test_views.py +++ b/tests/components/onboarding/test_views.py @@ -1,5 +1,6 @@ """Test the onboarding views.""" import asyncio +import os import pytest @@ -29,6 +30,57 @@ def auth_active(hass): ) +@pytest.fixture(name="rpi") +async def rpi_fixture(hass, aioclient_mock, mock_supervisor): + """Mock core info with rpi.""" + aioclient_mock.get( + "http://127.0.0.1/core/info", + json={ + "result": "ok", + "data": {"version_latest": "1.0.0", "machine": "raspberrypi3"}, + }, + ) + assert await async_setup_component(hass, "hassio", {}) + await hass.async_block_till_done() + + +@pytest.fixture(name="no_rpi") +async def no_rpi_fixture(hass, aioclient_mock, mock_supervisor): + """Mock core info with rpi.""" + aioclient_mock.get( + "http://127.0.0.1/core/info", + json={ + "result": "ok", + "data": {"version_latest": "1.0.0", "machine": "odroid-n2"}, + }, + ) + assert await async_setup_component(hass, "hassio", {}) + await hass.async_block_till_done() + + +@pytest.fixture(name="mock_supervisor") +async def mock_supervisor_fixture(hass, aioclient_mock): + """Mock supervisor.""" + aioclient_mock.post("http://127.0.0.1/homeassistant/options", json={"result": "ok"}) + aioclient_mock.post("http://127.0.0.1/supervisor/options", json={"result": "ok"}) + with patch.dict(os.environ, {"HASSIO": "127.0.0.1"}), patch( + "homeassistant.components.hassio.HassIO.is_connected", + return_value=True, + ), patch( + "homeassistant.components.hassio.HassIO.get_info", + return_value={}, + ), patch( + "homeassistant.components.hassio.HassIO.get_host_info", + return_value={}, + ), patch( + "homeassistant.components.hassio.HassIO.get_ingress_panels", + return_value={"panels": {}}, + ), patch.dict( + os.environ, {"HASSIO_TOKEN": "123456"} + ): + yield + + async def test_onboarding_progress(hass, hass_storage, aiohttp_client): """Test fetching progress.""" mock_storage(hass_storage, {"done": ["hello"]}) @@ -277,3 +329,51 @@ async def test_onboarding_core_sets_up_met(hass, hass_storage, hass_client): await hass.async_block_till_done() assert len(hass.states.async_entity_ids("weather")) == 1 + + +async def test_onboarding_core_sets_up_rpi_power( + hass, hass_storage, hass_client, aioclient_mock, rpi +): + """Test that the core step sets up rpi_power on RPi.""" + mock_storage(hass_storage, {"done": [const.STEP_USER]}) + await async_setup_component(hass, "persistent_notification", {}) + + assert await async_setup_component(hass, "onboarding", {}) + + client = await hass_client() + + with patch( + "homeassistant.components.rpi_power.config_flow.new_under_voltage" + ), patch("homeassistant.components.rpi_power.binary_sensor.new_under_voltage"): + resp = await client.post("/api/onboarding/core_config") + + assert resp.status == 200 + + await hass.async_block_till_done() + + rpi_power_state = hass.states.get("binary_sensor.rpi_power_status") + assert rpi_power_state + + +async def test_onboarding_core_no_rpi_power( + hass, hass_storage, hass_client, aioclient_mock, no_rpi +): + """Test that the core step do not set up rpi_power on non RPi.""" + mock_storage(hass_storage, {"done": [const.STEP_USER]}) + await async_setup_component(hass, "persistent_notification", {}) + + assert await async_setup_component(hass, "onboarding", {}) + + client = await hass_client() + + with patch( + "homeassistant.components.rpi_power.config_flow.new_under_voltage" + ), patch("homeassistant.components.rpi_power.binary_sensor.new_under_voltage"): + resp = await client.post("/api/onboarding/core_config") + + assert resp.status == 200 + + await hass.async_block_till_done() + + rpi_power_state = hass.states.get("binary_sensor.rpi_power_status") + assert not rpi_power_state diff --git a/tests/components/rpi_power/test_config_flow.py b/tests/components/rpi_power/test_config_flow.py index 70b384d6b91..090b6a6a793 100644 --- a/tests/components/rpi_power/test_config_flow.py +++ b/tests/components/rpi_power/test_config_flow.py @@ -14,7 +14,7 @@ from tests.common import patch MODULE = "homeassistant.components.rpi_power.config_flow.new_under_voltage" -async def test_setup(hass: HomeAssistant): +async def test_setup(hass: HomeAssistant) -> None: """Test setting up manually.""" result = await hass.config_entries.flow.async_init( DOMAIN, @@ -29,7 +29,7 @@ async def test_setup(hass: HomeAssistant): assert result["type"] == RESULT_TYPE_CREATE_ENTRY -async def test_not_supported(hass: HomeAssistant): +async def test_not_supported(hass: HomeAssistant) -> None: """Test setting up on not supported system.""" result = await hass.config_entries.flow.async_init( DOMAIN, @@ -40,3 +40,24 @@ async def test_not_supported(hass: HomeAssistant): result = await hass.config_entries.flow.async_configure(result["flow_id"], {}) assert result["type"] == RESULT_TYPE_ABORT assert result["reason"] == "no_devices_found" + + +async def test_onboarding(hass: HomeAssistant) -> None: + """Test setting up via onboarding.""" + with patch(MODULE, return_value=MagicMock()): + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": "onboarding"}, + ) + assert result["type"] == RESULT_TYPE_CREATE_ENTRY + + +async def test_onboarding_not_supported(hass: HomeAssistant) -> None: + """Test setting up via onboarding with unsupported system.""" + with patch(MODULE, return_value=None): + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": "onboarding"}, + ) + assert result["type"] == RESULT_TYPE_ABORT + assert result["reason"] == "no_devices_found"