Add basic Rhasspy integration (#74942)
Co-authored-by: Franck Nijhof <git@frenck.dev>
This commit is contained in:
parent
6ac05784a6
commit
6fd47d035e
13 changed files with 166 additions and 0 deletions
|
@ -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.*
|
||||
|
|
|
@ -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
|
||||
|
|
15
homeassistant/components/rhasspy/__init__.py
Normal file
15
homeassistant/components/rhasspy/__init__.py
Normal 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
|
29
homeassistant/components/rhasspy/config_flow.py
Normal file
29
homeassistant/components/rhasspy/config_flow.py
Normal 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={})
|
3
homeassistant/components/rhasspy/const.py
Normal file
3
homeassistant/components/rhasspy/const.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
"""Constants for the Rhasspy integration."""
|
||||
|
||||
DOMAIN = "rhasspy"
|
9
homeassistant/components/rhasspy/manifest.json
Normal file
9
homeassistant/components/rhasspy/manifest.json
Normal 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"
|
||||
}
|
12
homeassistant/components/rhasspy/strings.json
Normal file
12
homeassistant/components/rhasspy/strings.json
Normal 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%]"
|
||||
}
|
||||
}
|
||||
}
|
12
homeassistant/components/rhasspy/translations/en.json
Normal file
12
homeassistant/components/rhasspy/translations/en.json
Normal 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?"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -290,6 +290,7 @@ FLOWS = {
|
|||
"recollect_waste",
|
||||
"renault",
|
||||
"rfxtrx",
|
||||
"rhasspy",
|
||||
"ridwell",
|
||||
"ring",
|
||||
"risco",
|
||||
|
|
11
mypy.ini
11
mypy.ini
|
@ -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
|
||||
|
|
1
tests/components/rhasspy/__init__.py
Normal file
1
tests/components/rhasspy/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
"""Tests for the Rhasspy integration."""
|
44
tests/components/rhasspy/test_config_flow.py
Normal file
44
tests/components/rhasspy/test_config_flow.py
Normal 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"
|
26
tests/components/rhasspy/test_init.py
Normal file
26
tests/components/rhasspy/test_init.py
Normal 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
|
Loading…
Add table
Add a link
Reference in a new issue