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
27 changes: 11 additions & 16 deletions custom_components/schellenberg_usb/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,26 +221,21 @@ async def _await_subentry_result(
"""Await a calibration step and cast to SubentryFlowResult for mypy."""
return cast(SubentryFlowResult, await step_coro)

async def async_step_blind(
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> SubentryFlowResult:
"""Entry point when the user clicks the 'Add device' button.

Home Assistant calls async_step_{subentry_type}() where subentry_type is
the key returned by async_get_supported_subentry_types. Since our type is
'blind', we implement async_step_blind(). Delegates to async_step_menu
so the user can choose between auto-pair and manual-add.
Home Assistant initiates user-triggered subentry flows via the `user`
step (per HA config-subentry docs) — NOT async_step_{subentry_type}.
Show the menu so the user can choose between auto-pair and manual-add.
Selecting an option routes to async_step_{option}: 'pair' or
'manual_add'.
"""
_LOGGER.debug("Subentry blind flow initiated")
return await self.async_step_menu(user_input)

async def async_step_menu(
self, user_input: dict[str, Any] | None = None
) -> SubentryFlowResult:
"""Show menu: Pair automatically or Add manually."""
return self.async_show_menu(
step_id="menu",
menu_options=["user", "manual_add"],
menu_options=["pair", "manual_add"],
)

async def async_step_manual_add(
Expand Down Expand Up @@ -365,14 +360,14 @@ async def async_step_manual_position(
last_step=True,
)

async def async_step_user(
async def async_step_pair(
self, user_input: dict[str, Any] | None = None
) -> SubentryFlowResult:
"""Handle pairing initialization."""
_LOGGER.debug("Pairing step user input: %s", user_input)
"""Auto-pair: trigger stick pairing and wait for a device to respond."""
_LOGGER.debug("Pairing step input: %s", user_input)
if user_input is None:
_LOGGER.info("Showing pairing form")
return self.async_show_form(step_id="user", data_schema=vol.Schema({}))
return self.async_show_form(step_id="pair", data_schema=vol.Schema({}))

# Get the hub entry (parent config entry)
hub_entry = self._get_entry()
Expand Down
2 changes: 1 addition & 1 deletion custom_components/schellenberg_usb/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@
"manufacturer": "van ooijen"
}
],
"version": "1.1.0"
"version": "1.1.1"
}
4 changes: 2 additions & 2 deletions custom_components/schellenberg_usb/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
"menu": {
"title": "Add a blind",
"menu_options": {
"user": "Pair automatically",
"pair": "Pair automatically",
"manual_add": "Add manually (already paired)"
}
},
Expand All @@ -64,7 +64,7 @@
"initial_position": "Current position"
}
},
"user": {
"pair": {
"title": "Pair a new device",
"description": "Press the pair button to activate pairing mode on your Schellenberg USB stick. Then press the pairing button on your blind motor within 2 minutes.",
"submit": "Pair"
Expand Down
9 changes: 8 additions & 1 deletion custom_components/schellenberg_usb/translations/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,14 @@
"reconfigure": "Kalibrieren"
},
"step": {
"user": {
"menu": {
"title": "Rollladen hinzufügen",
"menu_options": {
"pair": "Automatisch koppeln",
"manual_add": "Manuell hinzufügen (bereits gekoppelt)"
}
},
"pair": {
"title": "Neues Gerät koppeln",
"description": "Drücken Sie die Kopplungstaste, um den Kopplungsmodus an Ihrem Schellenberg USB-Stick zu aktivieren. Drücken Sie dann innerhalb von 2 Minuten die Kopplungstaste an Ihrem Rollladenmotor.",
"submit": "Koppeln"
Expand Down
4 changes: 2 additions & 2 deletions custom_components/schellenberg_usb/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
"menu": {
"title": "Add a blind",
"menu_options": {
"user": "Pair automatically",
"pair": "Pair automatically",
"manual_add": "Add manually (already paired)"
}
},
Expand All @@ -64,7 +64,7 @@
"initial_position": "Current position"
}
},
"user": {
"pair": {
"title": "Pair a new device",
"description": "Press the pair button to activate pairing mode on your Schellenberg USB stick. Then press the pairing button on your blind motor within 2 minutes.",
"submit": "Pair"
Expand Down
9 changes: 8 additions & 1 deletion custom_components/schellenberg_usb/translations/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,14 @@
"reconfigure": "Calibrar"
},
"step": {
"user": {
"menu": {
"title": "Añadir una persiana",
"menu_options": {
"pair": "Emparejar automáticamente",
"manual_add": "Añadir manualmente (ya emparejado)"
}
},
"pair": {
"title": "Emparejar un nuevo dispositivo",
"description": "Presione el botón de emparejamiento para activar el modo de emparejamiento en su memoria USB Schellenberg. Luego presione el botón de emparejamiento en su motor de persiana en los próximos 2 minutos.",
"submit": "Emparejar"
Expand Down
9 changes: 8 additions & 1 deletion custom_components/schellenberg_usb/translations/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,14 @@
"reconfigure": "Calibrer"
},
"step": {
"user": {
"menu": {
"title": "Ajouter un volet",
"menu_options": {
"pair": "Appairer automatiquement",
"manual_add": "Ajouter manuellement (déjà appairé)"
}
},
"pair": {
"title": "Appairer un nouvel appareil",
"description": "Appuyez sur le bouton d'appairage pour activer le mode d'appairage sur votre clé USB Schellenberg. Ensuite, appuyez sur le bouton d'appairage de votre moteur de volet dans les 2 minutes.",
"submit": "Appairer"
Expand Down
24 changes: 21 additions & 3 deletions tests/test_config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,34 @@ def mock_hub_entry(hass: HomeAssistant) -> ConfigEntry:
async def test_manual_add_menu_shown(
hass: HomeAssistant, mock_hub_entry: ConfigEntry
) -> None:
"""Menu step returns show_menu with 'user' and 'manual_add' options."""
"""The flow entry step (async_step_user) shows the menu.

Regression: HA initiates user-triggered subentry flows via async_step_user,
NOT async_step_{subentry_type}. The menu must therefore be served from
async_step_user, with options routing to async_step_pair / async_step_manual_add.
"""
handler = _make_handler(hass, mock_hub_entry.entry_id)

result = await handler.async_step_blind(None)
result = await handler.async_step_user(None)

assert result["type"] == "menu"
assert "user" in result["menu_options"]
assert "pair" in result["menu_options"]
assert "manual_add" in result["menu_options"]


@pytest.mark.asyncio
async def test_pair_step_shows_form(
hass: HomeAssistant, mock_hub_entry: ConfigEntry
) -> None:
"""Selecting 'Pair automatically' (async_step_pair) shows the pairing form."""
handler = _make_handler(hass, mock_hub_entry.entry_id)

result = await handler.async_step_pair(None)

assert result["type"] == "form"
assert result["step_id"] == "pair"


@pytest.mark.asyncio
async def test_manual_add_creates_subentry(
hass: HomeAssistant, mock_hub_entry: ConfigEntry
Expand Down