Add basic Rhasspy integration (#74942)

Co-authored-by: Franck Nijhof <git@frenck.dev>
This commit is contained in:
Paulus Schoutsen 2022-07-11 08:40:52 -07:00 committed by GitHub
parent 6ac05784a6
commit 6fd47d035e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 166 additions and 0 deletions

View File

@ -193,6 +193,7 @@ homeassistant.components.recorder.*
homeassistant.components.remote.*
homeassistant.components.renault.*
homeassistant.components.resolution_center.*
homeassistant.components.rhasspy.*
homeassistant.components.ridwell.*
homeassistant.components.rituals_perfume_genie.*
homeassistant.components.roku.*

View File

@ -865,6 +865,8 @@ build.json @home-assistant/supervisor
/tests/components/rflink/ @javicalle
/homeassistant/components/rfxtrx/ @danielhiversen @elupus @RobBie1221
/tests/components/rfxtrx/ @danielhiversen @elupus @RobBie1221
/homeassistant/components/rhasspy/ @balloob @synesthesiam
/tests/components/rhasspy/ @balloob @synesthesiam
/homeassistant/components/ridwell/ @bachya
/tests/components/ridwell/ @bachya
/homeassistant/components/ring/ @balloob

View File

@ -0,0 +1,15 @@
"""The Rhasspy integration."""
from __future__ import annotations
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up Rhasspy from a config entry."""
return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry."""
return True

View File

@ -0,0 +1,29 @@
"""Config flow for Rhasspy integration."""
from __future__ import annotations
from typing import Any
import voluptuous as vol
from homeassistant import config_entries
from homeassistant.data_entry_flow import FlowResult
from .const import DOMAIN
class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle a config flow for Rhasspy."""
VERSION = 1
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
"""Handle the initial step."""
if self._async_current_entries():
return self.async_abort(reason="single_instance_allowed")
if user_input is None:
return self.async_show_form(step_id="user", data_schema=vol.Schema({}))
return self.async_create_entry(title="Rhasspy", data={})

View File

@ -0,0 +1,3 @@
"""Constants for the Rhasspy integration."""
DOMAIN = "rhasspy"

View File

@ -0,0 +1,9 @@
{
"domain": "rhasspy",
"name": "Rhasspy",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/rhasspy",
"dependencies": ["intent"],
"codeowners": ["@balloob", "@synesthesiam"],
"iot_class": "local_push"
}

View File

@ -0,0 +1,12 @@
{
"config": {
"step": {
"user": {
"description": "Do you want to enable Rhasspy support?"
}
},
"abort": {
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]"
}
}
}

View File

@ -0,0 +1,12 @@
{
"config": {
"abort": {
"single_instance_allowed": "Already configured. Only a single configuration possible."
},
"step": {
"user": {
"description": "Do you want to enable Rhasspy support?"
}
}
}
}

View File

@ -290,6 +290,7 @@ FLOWS = {
"recollect_waste",
"renault",
"rfxtrx",
"rhasspy",
"ridwell",
"ring",
"risco",

View File

@ -1886,6 +1886,17 @@ no_implicit_optional = true
warn_return_any = true
warn_unreachable = true
[mypy-homeassistant.components.rhasspy.*]
check_untyped_defs = true
disallow_incomplete_defs = true
disallow_subclassing_any = true
disallow_untyped_calls = true
disallow_untyped_decorators = true
disallow_untyped_defs = true
no_implicit_optional = true
warn_return_any = true
warn_unreachable = true
[mypy-homeassistant.components.ridwell.*]
check_untyped_defs = true
disallow_incomplete_defs = true

View File

@ -0,0 +1 @@
"""Tests for the Rhasspy integration."""

View File

@ -0,0 +1,44 @@
"""Test the Rhasspy config flow."""
from unittest.mock import patch
from homeassistant import config_entries
from homeassistant.components.rhasspy.const import DOMAIN
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType
from tests.common import MockConfigEntry
async def test_form(hass: HomeAssistant) -> None:
"""Test we get the form."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == FlowResultType.FORM
assert result["errors"] is None
with patch(
"homeassistant.components.rhasspy.async_setup_entry",
return_value=True,
) as mock_setup_entry:
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{},
)
await hass.async_block_till_done()
assert result2["type"] == FlowResultType.CREATE_ENTRY
assert result2["title"] == "Rhasspy"
assert result2["data"] == {}
assert len(mock_setup_entry.mock_calls) == 1
async def test_single_entry(hass: HomeAssistant) -> None:
"""Test we only allow single entry."""
MockConfigEntry(domain=DOMAIN).add_to_hass(hass)
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == FlowResultType.ABORT
assert result["reason"] == "single_instance_allowed"

View File

@ -0,0 +1,26 @@
"""Tests for the Rhasspy integration."""
from homeassistant.components.rhasspy.const import DOMAIN
from homeassistant.config_entries import ConfigEntryState
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry
async def test_load_unload_config_entry(hass: HomeAssistant) -> None:
"""Test the Rhasspy configuration entry loading/unloading."""
mock_config_entry = MockConfigEntry(
title="Rhasspy",
domain=DOMAIN,
data={},
)
mock_config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
assert mock_config_entry.state is ConfigEntryState.LOADED
await hass.config_entries.async_unload(mock_config_entry.entry_id)
await hass.async_block_till_done()
assert not hass.data.get(DOMAIN)
assert mock_config_entry.state is ConfigEntryState.NOT_LOADED