From d43d08d6c99b50e2ef94d6c080983c782d922f5e Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Mon, 14 Sep 2020 15:39:20 +0200 Subject: [PATCH 1/5] Add rpi_power onboarding step --- .../components/rpi_power/config_flow.py | 36 +++++++++++++++---- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/rpi_power/config_flow.py b/homeassistant/components/rpi_power/config_flow.py index 6112bddb7d5aa1..e19917ef970f30 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,29 @@ 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.""" + if self._async_current_entries(): + return self.async_abort(reason="single_instance_allowed") + + 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={}) From 8aaa44337ad24939d9e5ac080fd4e33a55e71db4 Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Mon, 14 Sep 2020 16:06:46 +0200 Subject: [PATCH 2/5] Start rpi_power config flow from onboarding on pi --- homeassistant/components/onboarding/manifest.json | 13 +++++++++++-- homeassistant/components/onboarding/views.py | 8 ++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/onboarding/manifest.json b/homeassistant/components/onboarding/manifest.json index 81e88e99edb23f..e2fb8e084b83b8 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 a2a4fb15fd74e4..0faf099b9bf0fb 100644 --- a/homeassistant/components/onboarding/views.py +++ b/homeassistant/components/onboarding/views.py @@ -159,6 +159,14 @@ async def post(self, request): "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({}) From e3446e2625944416373451e0ba7fb809b7691b37 Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Mon, 14 Sep 2020 16:58:09 +0200 Subject: [PATCH 3/5] Remove not needed check for onboarding --- homeassistant/components/rpi_power/config_flow.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/homeassistant/components/rpi_power/config_flow.py b/homeassistant/components/rpi_power/config_flow.py index e19917ef970f30..9924ebf0440cf2 100644 --- a/homeassistant/components/rpi_power/config_flow.py +++ b/homeassistant/components/rpi_power/config_flow.py @@ -34,9 +34,6 @@ async def async_step_onboarding( self, data: Optional[Dict[str, Any]] = None ) -> Dict[str, Any]: """Handle a flow initialized by onboarding.""" - if self._async_current_entries(): - return self.async_abort(reason="single_instance_allowed") - has_devices = await self._discovery_function(self.hass) if not has_devices: From f4fe4d9cc04ec3240cdc8de633b2901810006372 Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Mon, 14 Sep 2020 17:01:19 +0200 Subject: [PATCH 4/5] Add config flow onboarding tests --- .../components/rpi_power/test_config_flow.py | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/tests/components/rpi_power/test_config_flow.py b/tests/components/rpi_power/test_config_flow.py index 70b384d6b91c2f..090b6a6a793588 100644 --- a/tests/components/rpi_power/test_config_flow.py +++ b/tests/components/rpi_power/test_config_flow.py @@ -14,7 +14,7 @@ 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" From dd99cbc15cf4e45e8bb3d452f106b5e499aa0d87 Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Mon, 14 Sep 2020 19:20:18 +0200 Subject: [PATCH 5/5] Add onboarding tests --- tests/components/onboarding/test_views.py | 100 ++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/tests/components/onboarding/test_views.py b/tests/components/onboarding/test_views.py index 0d42564262215f..a1b857a52ceb00 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