Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions homeassistant/components/airly/quality_scale.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
rules:
# Bronze
action-setup:
status: exempt
comment: The integration does not register services.
appropriate-polling: done
brands: done
common-modules: done
config-flow-test-coverage:
status: todo
comment: The config flow test should either result in an entry being created or an abort.
config-flow:
status: todo
comment: Add data_description.
dependency-transparency: done
docs-actions:
status: exempt
comment: The integration does not register services.
docs-triggers:
status: exempt
comment: This integration does not have any triggers.
docs-conditions:
status: exempt
comment: This integration does not have any conditions.
docs-high-level-description: done
docs-installation-instructions: done
docs-removal-instructions: todo
entity-event-setup: done
entity-unique-id: done
has-entity-name: done
runtime-data: done
test-before-configure: done
test-before-setup: done
unique-config-entry: done

# Silver
action-exceptions:
status: exempt
comment: The integration does not register services.
config-entry-unloading: done
docs-configuration-parameters:
status: exempt
comment: The integration does not have an options flow.
docs-installation-parameters:
status: todo
comment: The documentation does not describe all setup parameters.
entity-unavailable: done
integration-owner: done
log-when-unavailable: done
parallel-updates:
status: todo
comment: PARALLEL_UPDATES should be changed to 0 as documentation suggests.
reauthentication-flow: todo
test-coverage: done

# Gold
devices: done
diagnostics: done
discovery-update-info:
status: exempt
comment: This integration is a cloud service and does not support discovery.
discovery:
status: exempt
comment: This integration is a cloud service and does not support discovery.
docs-data-update: done
docs-examples: todo
docs-known-limitations:
status: todo
comment: Add "No known limitations."
docs-supported-devices:
status: exempt
comment: This integration connects to a service, not supported devices.
docs-supported-functions:
status: todo
comment: The documentation does not describe the provided entities and platforms.
docs-troubleshooting: todo
docs-use-cases: todo
dynamic-devices:
status: exempt
comment: Each config entry represents a fixed Airly service location.
entity-category: done
entity-device-class: done
entity-disabled-by-default: done
entity-translations: done
exception-translations: done
icon-translations: done
reconfiguration-flow: todo
repair-issues:
status: exempt
comment: This integration does not raise any repairable issues.
stale-devices:
status: exempt
comment: Each config entry represents a fixed Airly service location.

# Platinum
async-dependency: done
inject-websession: done
strict-typing:
status: todo
comment: The 'airly' library is not PEP-561 compliant.
2 changes: 1 addition & 1 deletion homeassistant/components/elgato/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@
"integration_type": "device",
"iot_class": "local_polling",
"quality_scale": "platinum",
"requirements": ["elgato==5.1.2"],
"requirements": ["elgato==6.0.0"],
"zeroconf": ["_elg._tcp.local."]
}
119 changes: 96 additions & 23 deletions homeassistant/components/mcp_server/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,14 @@

import voluptuous as vol

from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
from homeassistant.config_entries import (
ConfigEntry,
ConfigFlow,
ConfigFlowResult,
OptionsFlow,
)
from homeassistant.const import CONF_LLM_HASS_API
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import llm
from homeassistant.helpers.selector import (
SelectOptionDict,
Expand All @@ -21,50 +27,117 @@
MORE_INFO_URL = "https://www.home-assistant.io/integrations/mcp_server/#configuration"


def _llm_api_names(hass: HomeAssistant) -> dict[str, str]:
"""Return the registered LLM API names keyed by API id."""
return {api.id: api.name for api in llm.async_get_apis(hass)}


def _llm_api_title(llm_apis: dict[str, str], api_ids: list[str]) -> str:
"""Return the entry title generated for the selected LLM APIs."""
return ", ".join(llm_apis[api_id] for api_id in api_ids if api_id in llm_apis)


def _selected_llm_apis(entry: ConfigEntry, llm_apis: dict[str, str]) -> list[str]:
"""Return the still registered LLM APIs selected by the config entry."""
api_ids = entry.data.get(CONF_LLM_HASS_API) or []
if isinstance(api_ids, str): # Old config entries stored a single API
api_ids = [api_ids]
return [api_id for api_id in api_ids if api_id in llm_apis]


def _llm_api_schema(llm_apis: dict[str, str], default: list[str]) -> vol.Schema:
"""Return the schema for selecting LLM APIs."""
return vol.Schema(
{
vol.Optional(
CONF_LLM_HASS_API,
default=default,
): SelectSelector(
SelectSelectorConfig(
options=[
SelectOptionDict(
label=name,
value=llm_api_id,
)
for llm_api_id, name in llm_apis.items()
],
multiple=True,
)
),
}
)


class ModelContextServerProtocolConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for Model Context Protocol Server."""

VERSION = 1

@staticmethod
@callback
@override
def async_get_options_flow(
config_entry: ConfigEntry,
) -> ModelContextServerProtocolOptionsFlow:
"""Create the options flow."""
return ModelContextServerProtocolOptionsFlow()

@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle the initial step."""
errors: dict[str, str] = {}
llm_apis = {api.id: api.name for api in llm.async_get_apis(self.hass)}
llm_apis = _llm_api_names(self.hass)
if user_input is not None:
if not user_input[CONF_LLM_HASS_API]:
errors[CONF_LLM_HASS_API] = "llm_api_required"
else:
return self.async_create_entry(
title=", ".join(
llm_apis[api_id] for api_id in user_input[CONF_LLM_HASS_API]
),
title=_llm_api_title(llm_apis, user_input[CONF_LLM_HASS_API]),
data=user_input,
)

return self.async_show_form(
step_id="user",
data_schema=vol.Schema(
{
vol.Optional(
CONF_LLM_HASS_API,
default=[llm.LLM_API_ASSIST],
): SelectSelector(
SelectSelectorConfig(
options=[
SelectOptionDict(
label=name,
value=llm_api_id,
)
for llm_api_id, name in llm_apis.items()
],
multiple=True,
)
),
data_schema=_llm_api_schema(llm_apis, [llm.LLM_API_ASSIST]),
description_placeholders={"more_info_url": MORE_INFO_URL},
errors=errors,
)


class ModelContextServerProtocolOptionsFlow(OptionsFlow):
"""Handle an options flow to change the exposed LLM APIs."""

async def async_step_init(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle the options step."""
errors: dict[str, str] = {}
llm_apis = _llm_api_names(self.hass)
current = _selected_llm_apis(self.config_entry, llm_apis)
if user_input is not None:
if not user_input[CONF_LLM_HASS_API]:
errors[CONF_LLM_HASS_API] = "llm_api_required"
else:
updates: dict[str, Any] = {
"data": {**self.config_entry.data, **user_input}
}
),
# Keep a title the user renamed, only refresh a generated one.
if self.config_entry.title == _llm_api_title(llm_apis, current):
updates["title"] = _llm_api_title(
llm_apis, user_input[CONF_LLM_HASS_API]
)
self.hass.config_entries.async_update_entry(
self.config_entry, **updates
)
# An open SSE session keeps serving the APIs it started with.
await self.hass.config_entries.async_reload(self.config_entry.entry_id)
return self.async_create_entry(data={})

return self.async_show_form(
step_id="init",
data_schema=_llm_api_schema(llm_apis, current),
description_placeholders={"more_info_url": MORE_INFO_URL},
errors=errors,
)
16 changes: 16 additions & 0 deletions homeassistant/components/mcp_server/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,21 @@
"description": "See the [integration documentation]({more_info_url}) for setup instructions."
}
}
},
"options": {
"error": {
"llm_api_required": "[%key:component::mcp_server::config::error::llm_api_required%]"
},
"step": {
"init": {
"data": {
"llm_hass_api": "[%key:common::config_flow::data::llm_hass_api%]"
},
"data_description": {
"llm_hass_api": "[%key:component::mcp_server::config::step::user::data_description::llm_hass_api%]"
},
"description": "[%key:component::mcp_server::config::step::user::description%]"
}
}
}
}
2 changes: 1 addition & 1 deletion homeassistant/components/nobo_hub/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

_LOGGER = logging.getLogger(__name__)

PLATFORMS = [Platform.CLIMATE, Platform.SELECT, Platform.SENSOR]
PLATFORMS = [Platform.CLIMATE, Platform.SELECT, Platform.SENSOR, Platform.SWITCH]

type NoboHubConfigEntry = ConfigEntry[nobo]

Expand Down
1 change: 1 addition & 0 deletions homeassistant/components/nobo_hub/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
ATTR_HARDWARE_VERSION: Final = "hardware_version"
ATTR_SOFTWARE_VERSION: Final = "software_version"
ATTR_SERIAL: Final = "serial"
ATTR_OVERRIDE_ALLOWED: Final = "override_allowed"
ATTR_TEMP_COMFORT_C: Final = "temp_comfort_c"
ATTR_TEMP_ECO_C: Final = "temp_eco_c"
ATTR_ZONE_ID: Final = "zone_id"
8 changes: 8 additions & 0 deletions homeassistant/components/nobo_hub/icons.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@
"week_profile": {
"default": "mdi:calendar-clock"
}
},
"switch": {
"disable_global_override": {
"default": "mdi:calendar-lock-open-outline",
"state": {
"on": "mdi:calendar-lock-outline"
}
}
}
}
}
6 changes: 1 addition & 5 deletions homeassistant/components/nobo_hub/quality_scale.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,7 @@ rules:
docs-troubleshooting: done
docs-use-cases: done
dynamic-devices: done
entity-category:
status: exempt
comment: >
All entities are primary controls or measurements; none are configuration
or diagnostic entities that need a non-default entity category.
entity-category: done
entity-device-class: done
entity-disabled-by-default:
status: exempt
Expand Down
8 changes: 8 additions & 0 deletions homeassistant/components/nobo_hub/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,20 @@
"week_profile": {
"name": "Week profile"
}
},
"switch": {
"disable_global_override": {
"name": "Disable global overrides"
}
}
},
"exceptions": {
"cannot_connect": {
"message": "Unable to connect to Nob酶 Ecohub with serial {serial} at {ip}; will retry. If the hub is on a different network from Home Assistant and has changed IP address, reconfigure the integration with the new IP address."
},
"set_disable_global_override_failed": {
"message": "Failed to change whether global overrides are disabled for the zone."
},
"set_global_override_failed": {
"message": "Failed to set global override."
},
Expand Down
Loading
Loading