diff --git a/homeassistant/components/homeassistant_yellow/__init__.py b/homeassistant/components/homeassistant_yellow/__init__.py
index 14c2de2c9a1fb3a364d18a854e606b16d3dd21be..04abe5a1dcae2de340f22ac5b3d50cbef0105797 100644
--- a/homeassistant/components/homeassistant_yellow/__init__.py
+++ b/homeassistant/components/homeassistant_yellow/__init__.py
@@ -2,18 +2,24 @@
 
 from __future__ import annotations
 
+import logging
+
 from homeassistant.components.hassio import get_os_info, is_hassio
 from homeassistant.components.homeassistant_hardware.silabs_multiprotocol_addon import (
     check_multi_pan_addon,
-    get_zigbee_socket,
-    multi_pan_addon_using_device,
+)
+from homeassistant.components.homeassistant_hardware.util import (
+    ApplicationType,
+    guess_firmware_type,
 )
 from homeassistant.config_entries import SOURCE_HARDWARE, ConfigEntry
 from homeassistant.core import HomeAssistant
 from homeassistant.exceptions import ConfigEntryNotReady, HomeAssistantError
 from homeassistant.helpers import discovery_flow
 
-from .const import RADIO_DEVICE, ZHA_HW_DISCOVERY_DATA
+from .const import FIRMWARE, RADIO_DEVICE, ZHA_HW_DISCOVERY_DATA
+
+_LOGGER = logging.getLogger(__name__)
 
 
 async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
@@ -27,34 +33,26 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
         # The hassio integration has not yet fetched data from the supervisor
         raise ConfigEntryNotReady
 
-    board: str | None
-    if (board := os_info.get("board")) is None or board != "yellow":
+    if os_info.get("board") != "yellow":
         # Not running on a Home Assistant Yellow, Home Assistant may have been migrated
         hass.async_create_task(hass.config_entries.async_remove(entry.entry_id))
         return False
 
-    try:
-        await check_multi_pan_addon(hass)
-    except HomeAssistantError as err:
-        raise ConfigEntryNotReady from err
-
-    if not await multi_pan_addon_using_device(hass, RADIO_DEVICE):
-        hw_discovery_data = ZHA_HW_DISCOVERY_DATA
-    else:
-        hw_discovery_data = {
-            "name": "Yellow Multiprotocol",
-            "port": {
-                "path": get_zigbee_socket(),
-            },
-            "radio_type": "ezsp",
-        }
-
-    discovery_flow.async_create_flow(
-        hass,
-        "zha",
-        context={"source": SOURCE_HARDWARE},
-        data=hw_discovery_data,
-    )
+    firmware = ApplicationType(entry.data[FIRMWARE])
+
+    if firmware is ApplicationType.CPC:
+        try:
+            await check_multi_pan_addon(hass)
+        except HomeAssistantError as err:
+            raise ConfigEntryNotReady from err
+
+    if firmware is ApplicationType.EZSP:
+        discovery_flow.async_create_flow(
+            hass,
+            "zha",
+            context={"source": SOURCE_HARDWARE},
+            data=ZHA_HW_DISCOVERY_DATA,
+        )
 
     return True
 
@@ -62,3 +60,39 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
 async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
     """Unload a config entry."""
     return True
+
+
+async def async_migrate_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
+    """Migrate old entry."""
+
+    _LOGGER.debug(
+        "Migrating from version %s.%s", config_entry.version, config_entry.minor_version
+    )
+
+    if config_entry.version == 1:
+        if config_entry.minor_version == 1:
+            # Add-on startup with type service get started before Core, always (e.g. the
+            # Multi-Protocol add-on). Probing the firmware would interfere with the add-on,
+            # so we can't safely probe here. Instead, we must make an educated guess!
+            firmware_guess = await guess_firmware_type(hass, RADIO_DEVICE)
+
+            new_data = {**config_entry.data}
+            new_data[FIRMWARE] = firmware_guess.firmware_type.value
+
+            hass.config_entries.async_update_entry(
+                config_entry,
+                data=new_data,
+                version=1,
+                minor_version=2,
+            )
+
+        _LOGGER.debug(
+            "Migration to version %s.%s successful",
+            config_entry.version,
+            config_entry.minor_version,
+        )
+
+        return True
+
+    # This means the user has downgraded from a future version
+    return False
diff --git a/homeassistant/components/homeassistant_yellow/config_flow.py b/homeassistant/components/homeassistant_yellow/config_flow.py
index d2212a968db12382ab35abec4226fe09e894e6aa..ce6475ceb3c25b537764c0e7e2a94f5505a49592 100644
--- a/homeassistant/components/homeassistant_yellow/config_flow.py
+++ b/homeassistant/components/homeassistant_yellow/config_flow.py
@@ -2,11 +2,13 @@
 
 from __future__ import annotations
 
+from abc import ABC, abstractmethod
 import asyncio
 import logging
-from typing import Any
+from typing import Any, final
 
 import aiohttp
+from universal_silabs_flasher.const import ApplicationType
 import voluptuous as vol
 
 from homeassistant.components.hassio import (
@@ -15,12 +17,25 @@ from homeassistant.components.hassio import (
     async_reboot_host,
     async_set_yellow_settings,
 )
-from homeassistant.components.homeassistant_hardware import silabs_multiprotocol_addon
-from homeassistant.config_entries import ConfigEntry, ConfigFlow, ConfigFlowResult
+from homeassistant.components.homeassistant_hardware.firmware_config_flow import (
+    BaseFirmwareConfigFlow,
+    BaseFirmwareOptionsFlow,
+)
+from homeassistant.components.homeassistant_hardware.silabs_multiprotocol_addon import (
+    OptionsFlowHandler as MultiprotocolOptionsFlowHandler,
+    SerialPortSettings as MultiprotocolSerialPortSettings,
+)
+from homeassistant.config_entries import (
+    SOURCE_HARDWARE,
+    ConfigEntry,
+    ConfigFlowResult,
+    OptionsFlow,
+)
 from homeassistant.core import callback
-from homeassistant.helpers import selector
+from homeassistant.helpers import discovery_flow, selector
 
-from .const import DOMAIN, ZHA_HW_DISCOVERY_DATA
+from .const import DOMAIN, FIRMWARE, RADIO_DEVICE, ZHA_DOMAIN, ZHA_HW_DISCOVERY_DATA
+from .hardware import BOARD_NAME
 
 _LOGGER = logging.getLogger(__name__)
 
@@ -33,18 +48,30 @@ STEP_HW_SETTINGS_SCHEMA = vol.Schema(
 )
 
 
-class HomeAssistantYellowConfigFlow(ConfigFlow, domain=DOMAIN):
+class HomeAssistantYellowConfigFlow(BaseFirmwareConfigFlow, domain=DOMAIN):
     """Handle a config flow for Home Assistant Yellow."""
 
     VERSION = 1
+    MINOR_VERSION = 2
+
+    def __init__(self, *args: Any, **kwargs: Any) -> None:
+        """Instantiate config flow."""
+        super().__init__(*args, **kwargs)
+
+        self._device = RADIO_DEVICE
 
     @staticmethod
     @callback
     def async_get_options_flow(
         config_entry: ConfigEntry,
-    ) -> HomeAssistantYellowOptionsFlow:
+    ) -> OptionsFlow:
         """Return the options flow."""
-        return HomeAssistantYellowOptionsFlow(config_entry)
+        firmware_type = ApplicationType(config_entry.data[FIRMWARE])
+
+        if firmware_type is ApplicationType.CPC:
+            return HomeAssistantYellowMultiPanOptionsFlowHandler(config_entry)
+
+        return HomeAssistantYellowOptionsFlowHandler(config_entry)
 
     async def async_step_system(
         self, data: dict[str, Any] | None = None
@@ -53,30 +80,56 @@ class HomeAssistantYellowConfigFlow(ConfigFlow, domain=DOMAIN):
         if self._async_current_entries():
             return self.async_abort(reason="single_instance_allowed")
 
-        return self.async_create_entry(title="Home Assistant Yellow", data={})
+        # We do not actually use any portion of `BaseFirmwareConfigFlow` beyond this
+        await self._probe_firmware_type()
+
+        # Kick off ZHA hardware discovery automatically if Zigbee firmware is running
+        if self._probed_firmware_type is ApplicationType.EZSP:
+            discovery_flow.async_create_flow(
+                self.hass,
+                ZHA_DOMAIN,
+                context={"source": SOURCE_HARDWARE},
+                data=ZHA_HW_DISCOVERY_DATA,
+            )
+
+        return self._async_flow_finished()
+
+    def _async_flow_finished(self) -> ConfigFlowResult:
+        """Create the config entry."""
+        assert self._probed_firmware_type is not None
+
+        return self.async_create_entry(
+            title=BOARD_NAME,
+            data={
+                # Assume the firmware type is EZSP if we cannot probe it
+                FIRMWARE: (self._probed_firmware_type or ApplicationType.EZSP).value,
+            },
+        )
 
 
-class HomeAssistantYellowOptionsFlow(silabs_multiprotocol_addon.OptionsFlowHandler):
-    """Handle an option flow for Home Assistant Yellow."""
+class BaseHomeAssistantYellowOptionsFlow(OptionsFlow, ABC):
+    """Base Home Assistant Yellow options flow shared between firmware and multi-PAN."""
 
     _hw_settings: dict[str, bool] | None = None
 
+    @abstractmethod
+    async def async_step_main_menu(self, _: None = None) -> ConfigFlowResult:
+        """Show the main menu."""
+
+    @final
+    async def async_step_init(
+        self, user_input: dict[str, Any] | None = None
+    ) -> ConfigFlowResult:
+        """Manage the options flow."""
+        return await self.async_step_main_menu()
+
+    @final
     async def async_step_on_supervisor(
         self, user_input: dict[str, Any] | None = None
     ) -> ConfigFlowResult:
         """Handle logic when on Supervisor host."""
         return await self.async_step_main_menu()
 
-    async def async_step_main_menu(self, _: None = None) -> ConfigFlowResult:
-        """Show the main menu."""
-        return self.async_show_menu(
-            step_id="main_menu",
-            menu_options=[
-                "hardware_settings",
-                "multipan_settings",
-            ],
-        )
-
     async def async_step_hardware_settings(
         self, user_input: dict[str, Any] | None = None
     ) -> ConfigFlowResult:
@@ -133,18 +186,36 @@ class HomeAssistantYellowOptionsFlow(silabs_multiprotocol_addon.OptionsFlowHandl
         """Reboot later."""
         return self.async_create_entry(data={})
 
+
+class HomeAssistantYellowMultiPanOptionsFlowHandler(
+    BaseHomeAssistantYellowOptionsFlow, MultiprotocolOptionsFlowHandler
+):
+    """Handle a multi-PAN options flow for Home Assistant Yellow."""
+
+    async def async_step_main_menu(self, _: None = None) -> ConfigFlowResult:
+        """Show the main menu."""
+        return self.async_show_menu(
+            step_id="main_menu",
+            menu_options=[
+                "hardware_settings",
+                "multipan_settings",
+            ],
+        )
+
     async def async_step_multipan_settings(
         self, user_input: dict[str, Any] | None = None
     ) -> ConfigFlowResult:
         """Handle multipan settings."""
-        return await super().async_step_on_supervisor(user_input)
+        return await MultiprotocolOptionsFlowHandler.async_step_on_supervisor(
+            self, user_input
+        )
 
     async def _async_serial_port_settings(
         self,
-    ) -> silabs_multiprotocol_addon.SerialPortSettings:
+    ) -> MultiprotocolSerialPortSettings:
         """Return the radio serial port settings."""
-        return silabs_multiprotocol_addon.SerialPortSettings(
-            device="/dev/ttyAMA1",
+        return MultiprotocolSerialPortSettings(
+            device=RADIO_DEVICE,
             baudrate="115200",
             flow_control=True,
         )
@@ -163,4 +234,64 @@ class HomeAssistantYellowOptionsFlow(silabs_multiprotocol_addon.OptionsFlowHandl
 
     def _hardware_name(self) -> str:
         """Return the name of the hardware."""
-        return "Home Assistant Yellow"
+        return BOARD_NAME
+
+    async def async_step_flashing_complete(
+        self, user_input: dict[str, Any] | None = None
+    ) -> ConfigFlowResult:
+        """Finish flashing and update the config entry."""
+        self.hass.config_entries.async_update_entry(
+            entry=self.config_entry,
+            data={
+                **self.config_entry.data,
+                FIRMWARE: ApplicationType.EZSP.value,
+            },
+        )
+
+        return await super().async_step_flashing_complete(user_input)
+
+
+class HomeAssistantYellowOptionsFlowHandler(
+    BaseHomeAssistantYellowOptionsFlow, BaseFirmwareOptionsFlow
+):
+    """Handle a firmware options flow for Home Assistant Yellow."""
+
+    def __init__(self, *args: Any, **kwargs: Any) -> None:
+        """Instantiate options flow."""
+        super().__init__(*args, **kwargs)
+
+        self._hardware_name = BOARD_NAME
+        self._device = RADIO_DEVICE
+
+        # Regenerate the translation placeholders
+        self._get_translation_placeholders()
+
+    async def async_step_main_menu(self, _: None = None) -> ConfigFlowResult:
+        """Show the main menu."""
+        return self.async_show_menu(
+            step_id="main_menu",
+            menu_options=[
+                "hardware_settings",
+                "firmware_settings",
+            ],
+        )
+
+    async def async_step_firmware_settings(
+        self, user_input: dict[str, Any] | None = None
+    ) -> ConfigFlowResult:
+        """Handle firmware configuration settings."""
+        return await super().async_step_pick_firmware()
+
+    def _async_flow_finished(self) -> ConfigFlowResult:
+        """Create the config entry."""
+        assert self._probed_firmware_type is not None
+
+        self.hass.config_entries.async_update_entry(
+            entry=self.config_entry,
+            data={
+                **self.config_entry.data,
+                FIRMWARE: self._probed_firmware_type.value,
+            },
+        )
+
+        return self.async_create_entry(title="", data={})
diff --git a/homeassistant/components/homeassistant_yellow/const.py b/homeassistant/components/homeassistant_yellow/const.py
index 8f1f9a4c2b8135c4c13a4c814a384451b9305c7d..79753ae9b9ec75d7154af7df0c0e674e9906e5a7 100644
--- a/homeassistant/components/homeassistant_yellow/const.py
+++ b/homeassistant/components/homeassistant_yellow/const.py
@@ -12,3 +12,6 @@ ZHA_HW_DISCOVERY_DATA = {
     },
     "radio_type": "efr32",
 }
+
+FIRMWARE = "firmware"
+ZHA_DOMAIN = "zha"
diff --git a/homeassistant/components/homeassistant_yellow/strings.json b/homeassistant/components/homeassistant_yellow/strings.json
index 95442d315003ac454abd123fecd48e10256350bc..fd3be3586b1b597fa4e6c8d733c7726ccf7f27d1 100644
--- a/homeassistant/components/homeassistant_yellow/strings.json
+++ b/homeassistant/components/homeassistant_yellow/strings.json
@@ -42,6 +42,7 @@
       "main_menu": {
         "menu_options": {
           "hardware_settings": "[%key:component::homeassistant_yellow::options::step::hardware_settings::title%]",
+          "firmware_settings": "Switch between Zigbee or Thread firmware.",
           "multipan_settings": "Configure IEEE 802.15.4 radio multiprotocol support"
         }
       },
@@ -79,6 +80,46 @@
       "start_flasher_addon": {
         "title": "[%key:component::homeassistant_hardware::silabs_multiprotocol_hardware::options::step::start_flasher_addon::title%]",
         "description": "[%key:component::homeassistant_hardware::silabs_multiprotocol_hardware::options::step::start_flasher_addon::description%]"
+      },
+      "pick_firmware": {
+        "title": "[%key:component::homeassistant_hardware::firmware_picker::options::step::pick_firmware::title%]",
+        "description": "[%key:component::homeassistant_hardware::firmware_picker::options::step::pick_firmware::description%]",
+        "menu_options": {
+          "pick_firmware_thread": "[%key:component::homeassistant_hardware::firmware_picker::options::step::pick_firmware::menu_options::pick_firmware_thread%]",
+          "pick_firmware_zigbee": "[%key:component::homeassistant_hardware::firmware_picker::options::step::pick_firmware::menu_options::pick_firmware_zigbee%]"
+        }
+      },
+      "install_zigbee_flasher_addon": {
+        "title": "[%key:component::homeassistant_hardware::firmware_picker::options::step::install_zigbee_flasher_addon::title%]",
+        "description": "[%key:component::homeassistant_hardware::firmware_picker::options::step::install_zigbee_flasher_addon::description%]"
+      },
+      "run_zigbee_flasher_addon": {
+        "title": "[%key:component::homeassistant_hardware::firmware_picker::options::step::run_zigbee_flasher_addon::title%]",
+        "description": "[%key:component::homeassistant_hardware::firmware_picker::options::step::run_zigbee_flasher_addon::description%]"
+      },
+      "zigbee_flasher_failed": {
+        "title": "[%key:component::homeassistant_hardware::firmware_picker::options::step::zigbee_flasher_failed::title%]",
+        "description": "[%key:component::homeassistant_hardware::firmware_picker::options::step::zigbee_flasher_failed::description%]"
+      },
+      "confirm_zigbee": {
+        "title": "[%key:component::homeassistant_hardware::firmware_picker::options::step::confirm_zigbee::title%]",
+        "description": "[%key:component::homeassistant_hardware::firmware_picker::options::step::confirm_zigbee::description%]"
+      },
+      "install_otbr_addon": {
+        "title": "[%key:component::homeassistant_hardware::firmware_picker::options::step::install_otbr_addon::title%]",
+        "description": "[%key:component::homeassistant_hardware::firmware_picker::options::step::install_otbr_addon::description%]"
+      },
+      "start_otbr_addon": {
+        "title": "[%key:component::homeassistant_hardware::firmware_picker::options::step::start_otbr_addon::title%]",
+        "description": "[%key:component::homeassistant_hardware::firmware_picker::options::step::start_otbr_addon::description%]"
+      },
+      "otbr_failed": {
+        "title": "[%key:component::homeassistant_hardware::firmware_picker::options::step::otbr_failed::title%]",
+        "description": "[%key:component::homeassistant_hardware::firmware_picker::options::step::otbr_failed::description%]"
+      },
+      "confirm_otbr": {
+        "title": "[%key:component::homeassistant_hardware::firmware_picker::options::step::confirm_otbr::title%]",
+        "description": "[%key:component::homeassistant_hardware::firmware_picker::options::step::confirm_otbr::description%]"
       }
     },
     "error": {
@@ -93,11 +134,19 @@
       "not_hassio": "[%key:component::homeassistant_hardware::silabs_multiprotocol_hardware::options::abort::not_hassio%]",
       "read_hw_settings_error": "Failed to read hardware settings",
       "write_hw_settings_error": "Failed to write hardware settings",
-      "zha_migration_failed": "[%key:component::homeassistant_hardware::silabs_multiprotocol_hardware::options::abort::zha_migration_failed%]"
+      "zha_migration_failed": "[%key:component::homeassistant_hardware::silabs_multiprotocol_hardware::options::abort::zha_migration_failed%]",
+      "not_hassio_thread": "[%key:component::homeassistant_hardware::firmware_picker::options::abort::not_hassio_thread%]",
+      "otbr_addon_already_running": "[%key:component::homeassistant_hardware::firmware_picker::options::abort::otbr_addon_already_running%]",
+      "zha_still_using_stick": "[%key:component::homeassistant_hardware::firmware_picker::options::abort::zha_still_using_stick%]",
+      "otbr_still_using_stick": "[%key:component::homeassistant_hardware::firmware_picker::options::abort::otbr_still_using_stick%]"
     },
     "progress": {
       "install_addon": "[%key:component::homeassistant_hardware::silabs_multiprotocol_hardware::options::progress::install_addon%]",
-      "start_addon": "[%key:component::homeassistant_hardware::silabs_multiprotocol_hardware::options::progress::start_addon%]"
+      "start_addon": "[%key:component::homeassistant_hardware::silabs_multiprotocol_hardware::options::progress::start_addon%]",
+      "start_otbr_addon": "[%key:component::homeassistant_hardware::silabs_multiprotocol_hardware::options::progress::start_addon%]",
+      "install_zigbee_flasher_addon": "[%key:component::homeassistant_hardware::firmware_picker::options::progress::install_zigbee_flasher_addon%]",
+      "run_zigbee_flasher_addon": "[%key:component::homeassistant_hardware::firmware_picker::options::progress::run_zigbee_flasher_addon%]",
+      "uninstall_zigbee_flasher_addon": "[%key:component::homeassistant_hardware::firmware_picker::options::progress::uninstall_zigbee_flasher_addon%]"
     }
   }
 }
diff --git a/tests/components/homeassistant_yellow/test_config_flow.py b/tests/components/homeassistant_yellow/test_config_flow.py
index 95d7df89c9d53523269039fcb4adef1db5dea22c..949e58e61b66015864eac57700739a2e94ee5622 100644
--- a/tests/components/homeassistant_yellow/test_config_flow.py
+++ b/tests/components/homeassistant_yellow/test_config_flow.py
@@ -6,8 +6,17 @@ from unittest.mock import Mock, patch
 import pytest
 
 from homeassistant.components.hassio import DOMAIN as HASSIO_DOMAIN
-from homeassistant.components.homeassistant_yellow.const import DOMAIN
-from homeassistant.components.zha import DOMAIN as ZHA_DOMAIN
+from homeassistant.components.hassio.addon_manager import AddonInfo, AddonState
+from homeassistant.components.homeassistant_hardware.firmware_config_flow import (
+    STEP_PICK_FIRMWARE_ZIGBEE,
+)
+from homeassistant.components.homeassistant_hardware.silabs_multiprotocol_addon import (
+    CONF_DISABLE_MULTI_PAN,
+    get_flasher_addon_manager,
+    get_multiprotocol_addon_manager,
+)
+from homeassistant.components.homeassistant_hardware.util import ApplicationType
+from homeassistant.components.homeassistant_yellow.const import DOMAIN, RADIO_DEVICE
 from homeassistant.core import HomeAssistant
 from homeassistant.data_entry_flow import FlowResultType
 from homeassistant.setup import async_setup_component
@@ -57,22 +66,28 @@ async def test_config_flow(hass: HomeAssistant) -> None:
     mock_integration(hass, MockModule("hassio"))
     await async_setup_component(hass, HASSIO_DOMAIN, {})
 
-    with patch(
-        "homeassistant.components.homeassistant_yellow.async_setup_entry",
-        return_value=True,
-    ) as mock_setup_entry:
+    with (
+        patch(
+            "homeassistant.components.homeassistant_yellow.async_setup_entry",
+            return_value=True,
+        ) as mock_setup_entry,
+        patch(
+            "homeassistant.components.homeassistant_hardware.firmware_config_flow.probe_silabs_firmware_type",
+            return_value=ApplicationType.EZSP,
+        ),
+    ):
         result = await hass.config_entries.flow.async_init(
             DOMAIN, context={"source": "system"}
         )
 
     assert result["type"] is FlowResultType.CREATE_ENTRY
     assert result["title"] == "Home Assistant Yellow"
-    assert result["data"] == {}
+    assert result["data"] == {"firmware": "ezsp"}
     assert result["options"] == {}
     assert len(mock_setup_entry.mock_calls) == 1
 
     config_entry = hass.config_entries.async_entries(DOMAIN)[0]
-    assert config_entry.data == {}
+    assert config_entry.data == {"firmware": "ezsp"}
     assert config_entry.options == {}
     assert config_entry.title == "Home Assistant Yellow"
 
@@ -84,10 +99,12 @@ async def test_config_flow_single_entry(hass: HomeAssistant) -> None:
 
     # Setup the config entry
     config_entry = MockConfigEntry(
-        data={},
+        data={"firmware": ApplicationType.EZSP},
         domain=DOMAIN,
         options={},
         title="Home Assistant Yellow",
+        version=1,
+        minor_version=2,
     )
     config_entry.add_to_hass(hass)
 
@@ -104,165 +121,6 @@ async def test_config_flow_single_entry(hass: HomeAssistant) -> None:
     mock_setup_entry.assert_not_called()
 
 
-async def test_option_flow_install_multi_pan_addon(
-    hass: HomeAssistant,
-    addon_store_info,
-    addon_info,
-    install_addon,
-    set_addon_options,
-    start_addon,
-) -> None:
-    """Test installing the multi pan addon."""
-    mock_integration(hass, MockModule("hassio"))
-    await async_setup_component(hass, HASSIO_DOMAIN, {})
-
-    # Setup the config entry
-    config_entry = MockConfigEntry(
-        data={},
-        domain=DOMAIN,
-        options={},
-        title="Home Assistant Yellow",
-    )
-    config_entry.add_to_hass(hass)
-
-    result = await hass.config_entries.options.async_init(config_entry.entry_id)
-    assert result["type"] is FlowResultType.MENU
-
-    with patch(
-        "homeassistant.components.homeassistant_hardware.silabs_multiprotocol_addon.is_hassio",
-        side_effect=Mock(return_value=True),
-    ):
-        result = await hass.config_entries.options.async_configure(
-            result["flow_id"],
-            {"next_step_id": "multipan_settings"},
-        )
-        assert result["type"] is FlowResultType.FORM
-        assert result["step_id"] == "addon_not_installed"
-
-    result = await hass.config_entries.options.async_configure(
-        result["flow_id"],
-        user_input={
-            "enable_multi_pan": True,
-        },
-    )
-    assert result["type"] is FlowResultType.SHOW_PROGRESS
-    assert result["step_id"] == "install_addon"
-    assert result["progress_action"] == "install_addon"
-
-    await hass.async_block_till_done()
-    install_addon.assert_called_once_with(hass, "core_silabs_multiprotocol")
-
-    result = await hass.config_entries.options.async_configure(result["flow_id"])
-    assert result["type"] is FlowResultType.SHOW_PROGRESS
-    assert result["step_id"] == "start_addon"
-    set_addon_options.assert_called_once_with(
-        hass,
-        "core_silabs_multiprotocol",
-        {
-            "options": {
-                "autoflash_firmware": True,
-                "device": "/dev/ttyAMA1",
-                "baudrate": "115200",
-                "flow_control": True,
-            }
-        },
-    )
-
-    await hass.async_block_till_done()
-    start_addon.assert_called_once_with(hass, "core_silabs_multiprotocol")
-
-    result = await hass.config_entries.options.async_configure(result["flow_id"])
-    assert result["type"] is FlowResultType.CREATE_ENTRY
-
-
-async def test_option_flow_install_multi_pan_addon_zha(
-    hass: HomeAssistant,
-    addon_store_info,
-    addon_info,
-    install_addon,
-    set_addon_options,
-    start_addon,
-) -> None:
-    """Test installing the multi pan addon when a zha config entry exists."""
-    mock_integration(hass, MockModule("hassio"))
-    await async_setup_component(hass, HASSIO_DOMAIN, {})
-
-    # Setup the config entry
-    config_entry = MockConfigEntry(
-        data={},
-        domain=DOMAIN,
-        options={},
-        title="Home Assistant Yellow",
-    )
-    config_entry.add_to_hass(hass)
-
-    zha_config_entry = MockConfigEntry(
-        data={"device": {"path": "/dev/ttyAMA1"}, "radio_type": "ezsp"},
-        domain=ZHA_DOMAIN,
-        options={},
-        title="Yellow",
-    )
-    zha_config_entry.add_to_hass(hass)
-
-    result = await hass.config_entries.options.async_init(config_entry.entry_id)
-    assert result["type"] is FlowResultType.MENU
-
-    with patch(
-        "homeassistant.components.homeassistant_hardware.silabs_multiprotocol_addon.is_hassio",
-        side_effect=Mock(return_value=True),
-    ):
-        result = await hass.config_entries.options.async_configure(
-            result["flow_id"],
-            {"next_step_id": "multipan_settings"},
-        )
-        assert result["type"] is FlowResultType.FORM
-        assert result["step_id"] == "addon_not_installed"
-
-    result = await hass.config_entries.options.async_configure(
-        result["flow_id"],
-        user_input={
-            "enable_multi_pan": True,
-        },
-    )
-    assert result["type"] is FlowResultType.SHOW_PROGRESS
-    assert result["step_id"] == "install_addon"
-    assert result["progress_action"] == "install_addon"
-
-    await hass.async_block_till_done()
-    install_addon.assert_called_once_with(hass, "core_silabs_multiprotocol")
-
-    result = await hass.config_entries.options.async_configure(result["flow_id"])
-    assert result["type"] is FlowResultType.SHOW_PROGRESS
-    assert result["step_id"] == "start_addon"
-    set_addon_options.assert_called_once_with(
-        hass,
-        "core_silabs_multiprotocol",
-        {
-            "options": {
-                "autoflash_firmware": True,
-                "device": "/dev/ttyAMA1",
-                "baudrate": "115200",
-                "flow_control": True,
-            }
-        },
-    )
-    # Check the ZHA config entry data is updated
-    assert zha_config_entry.data == {
-        "device": {
-            "path": "socket://core-silabs-multiprotocol:9999",
-            "baudrate": 115200,
-            "flow_control": None,
-        },
-        "radio_type": "ezsp",
-    }
-
-    await hass.async_block_till_done()
-    start_addon.assert_called_once_with(hass, "core_silabs_multiprotocol")
-
-    result = await hass.config_entries.options.async_configure(result["flow_id"])
-    assert result["type"] is FlowResultType.CREATE_ENTRY
-
-
 @pytest.mark.parametrize(
     ("reboot_menu_choice", "reboot_calls"),
     [("reboot_now", 1), ("reboot_later", 0)],
@@ -281,10 +139,12 @@ async def test_option_flow_led_settings(
 
     # Setup the config entry
     config_entry = MockConfigEntry(
-        data={},
+        data={"firmware": ApplicationType.EZSP},
         domain=DOMAIN,
         options={},
         title="Home Assistant Yellow",
+        version=1,
+        minor_version=2,
     )
     config_entry.add_to_hass(hass)
 
@@ -327,10 +187,12 @@ async def test_option_flow_led_settings_unchanged(
 
     # Setup the config entry
     config_entry = MockConfigEntry(
-        data={},
+        data={"firmware": ApplicationType.EZSP},
         domain=DOMAIN,
         options={},
         title="Home Assistant Yellow",
+        version=1,
+        minor_version=2,
     )
     config_entry.add_to_hass(hass)
 
@@ -359,10 +221,12 @@ async def test_option_flow_led_settings_fail_1(hass: HomeAssistant) -> None:
 
     # Setup the config entry
     config_entry = MockConfigEntry(
-        data={},
+        data={"firmware": ApplicationType.EZSP},
         domain=DOMAIN,
         options={},
         title="Home Assistant Yellow",
+        version=1,
+        minor_version=2,
     )
     config_entry.add_to_hass(hass)
 
@@ -391,10 +255,12 @@ async def test_option_flow_led_settings_fail_2(
 
     # Setup the config entry
     config_entry = MockConfigEntry(
-        data={},
+        data={"firmware": ApplicationType.EZSP},
         domain=DOMAIN,
         options={},
         title="Home Assistant Yellow",
+        version=1,
+        minor_version=2,
     )
     config_entry.add_to_hass(hass)
 
@@ -418,3 +284,139 @@ async def test_option_flow_led_settings_fail_2(
         )
     assert result["type"] is FlowResultType.ABORT
     assert result["reason"] == "write_hw_settings_error"
+
+
+async def test_firmware_options_flow(hass: HomeAssistant) -> None:
+    """Test the firmware options flow for Yellow."""
+    mock_integration(hass, MockModule("hassio"))
+    await async_setup_component(hass, HASSIO_DOMAIN, {})
+
+    config_entry = MockConfigEntry(
+        data={"firmware": ApplicationType.SPINEL},
+        domain=DOMAIN,
+        options={},
+        title="Home Assistant Yellow",
+        version=1,
+        minor_version=2,
+    )
+    config_entry.add_to_hass(hass)
+
+    # First step is confirmation
+    result = await hass.config_entries.options.async_init(config_entry.entry_id)
+    assert result["type"] is FlowResultType.MENU
+    assert result["step_id"] == "main_menu"
+    assert "firmware_settings" in result["menu_options"]
+
+    # Pick firmware settings
+    result = await hass.config_entries.options.async_configure(
+        result["flow_id"],
+        user_input={"next_step_id": "firmware_settings"},
+    )
+
+    assert result["step_id"] == "pick_firmware"
+    assert result["description_placeholders"]["firmware_type"] == "spinel"
+    assert result["description_placeholders"]["model"] == "Home Assistant Yellow"
+
+    async def mock_async_step_pick_firmware_zigbee(self, data):
+        return await self.async_step_confirm_zigbee(user_input={})
+
+    with patch(
+        "homeassistant.components.homeassistant_hardware.firmware_config_flow.BaseFirmwareOptionsFlow.async_step_pick_firmware_zigbee",
+        autospec=True,
+        side_effect=mock_async_step_pick_firmware_zigbee,
+    ):
+        result = await hass.config_entries.options.async_configure(
+            result["flow_id"],
+            user_input={"next_step_id": STEP_PICK_FIRMWARE_ZIGBEE},
+        )
+
+    assert result["type"] is FlowResultType.CREATE_ENTRY
+    assert result["result"] is True
+
+    assert config_entry.data == {
+        "firmware": "ezsp",
+    }
+
+
+async def test_options_flow_multipan_uninstall(hass: HomeAssistant) -> None:
+    """Test options flow for when multi-PAN firmware is installed."""
+    mock_integration(hass, MockModule("hassio"))
+    await async_setup_component(hass, HASSIO_DOMAIN, {})
+
+    config_entry = MockConfigEntry(
+        data={"firmware": ApplicationType.CPC},
+        domain=DOMAIN,
+        options={},
+        title="Home Assistant Yellow",
+        version=1,
+        minor_version=2,
+    )
+    config_entry.add_to_hass(hass)
+
+    # Multi-PAN addon is running
+    mock_multipan_manager = Mock(spec_set=await get_multiprotocol_addon_manager(hass))
+    mock_multipan_manager.async_get_addon_info.return_value = AddonInfo(
+        available=True,
+        hostname=None,
+        options={"device": RADIO_DEVICE},
+        state=AddonState.RUNNING,
+        update_available=False,
+        version="1.0.0",
+    )
+
+    mock_flasher_manager = Mock(spec_set=get_flasher_addon_manager(hass))
+    mock_flasher_manager.async_get_addon_info.return_value = AddonInfo(
+        available=True,
+        hostname=None,
+        options={},
+        state=AddonState.NOT_RUNNING,
+        update_available=False,
+        version="1.0.0",
+    )
+
+    with (
+        patch(
+            "homeassistant.components.homeassistant_hardware.silabs_multiprotocol_addon.get_multiprotocol_addon_manager",
+            return_value=mock_multipan_manager,
+        ),
+        patch(
+            "homeassistant.components.homeassistant_hardware.silabs_multiprotocol_addon.get_flasher_addon_manager",
+            return_value=mock_flasher_manager,
+        ),
+        patch(
+            "homeassistant.components.homeassistant_hardware.silabs_multiprotocol_addon.is_hassio",
+            return_value=True,
+        ),
+    ):
+        result = await hass.config_entries.options.async_init(config_entry.entry_id)
+        assert result["type"] is FlowResultType.MENU
+        assert result["step_id"] == "main_menu"
+        assert "multipan_settings" in result["menu_options"]
+
+        # Pick multi-PAN settings
+        result = await hass.config_entries.options.async_configure(
+            result["flow_id"],
+            user_input={"next_step_id": "multipan_settings"},
+        )
+
+        # Pick the uninstall option
+        result = await hass.config_entries.options.async_configure(
+            result["flow_id"],
+            user_input={"next_step_id": "uninstall_addon"},
+        )
+
+        # Check the box
+        result = await hass.config_entries.options.async_configure(
+            result["flow_id"], user_input={CONF_DISABLE_MULTI_PAN: True}
+        )
+
+        # Finish the flow
+        result = await hass.config_entries.options.async_configure(result["flow_id"])
+        await hass.async_block_till_done(wait_background_tasks=True)
+        result = await hass.config_entries.options.async_configure(result["flow_id"])
+        await hass.async_block_till_done(wait_background_tasks=True)
+        result = await hass.config_entries.options.async_configure(result["flow_id"])
+        assert result["type"] is FlowResultType.CREATE_ENTRY
+
+    # We've reverted the firmware back to Zigbee
+    assert config_entry.data["firmware"] == "ezsp"
diff --git a/tests/components/homeassistant_yellow/test_init.py b/tests/components/homeassistant_yellow/test_init.py
index ec3ba4e700569e61e36af69f8789dd4bf74285af..5d534dad1e7876cae1ce70062d500412660b15ec 100644
--- a/tests/components/homeassistant_yellow/test_init.py
+++ b/tests/components/homeassistant_yellow/test_init.py
@@ -6,10 +6,14 @@ import pytest
 
 from homeassistant.components import zha
 from homeassistant.components.hassio import DOMAIN as HASSIO_DOMAIN
-from homeassistant.components.hassio.handler import HassioAPIError
+from homeassistant.components.homeassistant_hardware.util import (
+    ApplicationType,
+    FirmwareGuess,
+)
 from homeassistant.components.homeassistant_yellow.const import DOMAIN
 from homeassistant.config_entries import ConfigEntryState
 from homeassistant.core import HomeAssistant
+from homeassistant.exceptions import HomeAssistantError
 from homeassistant.setup import async_setup_component
 
 from tests.common import MockConfigEntry, MockModule, mock_integration
@@ -27,10 +31,12 @@ async def test_setup_entry(
 
     # Setup the config entry
     config_entry = MockConfigEntry(
-        data={},
+        data={"firmware": ApplicationType.EZSP},
         domain=DOMAIN,
         options={},
         title="Home Assistant Yellow",
+        version=1,
+        minor_version=2,
     )
     config_entry.add_to_hass(hass)
     with (
@@ -42,6 +48,14 @@ async def test_setup_entry(
             "homeassistant.components.onboarding.async_is_onboarded",
             return_value=onboarded,
         ),
+        patch(
+            "homeassistant.components.homeassistant_yellow.guess_firmware_type",
+            return_value=FirmwareGuess(  # Nothing is setup
+                is_running=False,
+                firmware_type=ApplicationType.EZSP,
+                source="unknown",
+            ),
+        ),
     ):
         assert await hass.config_entries.async_setup(config_entry.entry_id)
         await hass.async_block_till_done(wait_background_tasks=True)
@@ -74,118 +88,12 @@ async def test_setup_zha(hass: HomeAssistant, addon_store_info) -> None:
 
     # Setup the config entry
     config_entry = MockConfigEntry(
-        data={},
-        domain=DOMAIN,
-        options={},
-        title="Home Assistant Yellow",
-    )
-    config_entry.add_to_hass(hass)
-    with (
-        patch(
-            "homeassistant.components.homeassistant_yellow.get_os_info",
-            return_value={"board": "yellow"},
-        ) as mock_get_os_info,
-        patch(
-            "homeassistant.components.onboarding.async_is_onboarded", return_value=False
-        ),
-    ):
-        assert await hass.config_entries.async_setup(config_entry.entry_id)
-        await hass.async_block_till_done(wait_background_tasks=True)
-        assert len(mock_get_os_info.mock_calls) == 1
-
-    # Finish setting up ZHA
-    zha_flows = hass.config_entries.flow.async_progress_by_handler("zha")
-    assert len(zha_flows) == 1
-    assert zha_flows[0]["step_id"] == "choose_formation_strategy"
-
-    await hass.config_entries.flow.async_configure(
-        zha_flows[0]["flow_id"],
-        user_input={"next_step_id": zha.config_flow.FORMATION_REUSE_SETTINGS},
-    )
-    await hass.async_block_till_done()
-
-    config_entry = hass.config_entries.async_entries("zha")[0]
-    assert config_entry.data == {
-        "device": {
-            "baudrate": 115200,
-            "flow_control": "hardware",
-            "path": "/dev/ttyAMA1",
-        },
-        "radio_type": "ezsp",
-    }
-    assert config_entry.options == {}
-    assert config_entry.title == "Yellow"
-
-
-async def test_setup_zha_multipan(
-    hass: HomeAssistant, addon_info, addon_running
-) -> None:
-    """Test zha gets the right config."""
-    mock_integration(hass, MockModule("hassio"))
-    await async_setup_component(hass, HASSIO_DOMAIN, {})
-
-    addon_info.return_value["options"]["device"] = "/dev/ttyAMA1"
-
-    # Setup the config entry
-    config_entry = MockConfigEntry(
-        data={},
-        domain=DOMAIN,
-        options={},
-        title="Home Assistant Yellow",
-    )
-    config_entry.add_to_hass(hass)
-    with (
-        patch(
-            "homeassistant.components.homeassistant_yellow.get_os_info",
-            return_value={"board": "yellow"},
-        ) as mock_get_os_info,
-        patch(
-            "homeassistant.components.onboarding.async_is_onboarded", return_value=False
-        ),
-    ):
-        assert await hass.config_entries.async_setup(config_entry.entry_id)
-        await hass.async_block_till_done(wait_background_tasks=True)
-        assert len(mock_get_os_info.mock_calls) == 1
-
-    # Finish setting up ZHA
-    zha_flows = hass.config_entries.flow.async_progress_by_handler("zha")
-    assert len(zha_flows) == 1
-    assert zha_flows[0]["step_id"] == "choose_formation_strategy"
-
-    await hass.config_entries.flow.async_configure(
-        zha_flows[0]["flow_id"],
-        user_input={"next_step_id": zha.config_flow.FORMATION_REUSE_SETTINGS},
-    )
-    await hass.async_block_till_done()
-
-    config_entry = hass.config_entries.async_entries("zha")[0]
-    assert config_entry.data == {
-        "device": {
-            "baudrate": 115200,
-            "flow_control": None,
-            "path": "socket://core-silabs-multiprotocol:9999",
-        },
-        "radio_type": "ezsp",
-    }
-    assert config_entry.options == {}
-    assert config_entry.title == "Yellow Multiprotocol"
-
-
-async def test_setup_zha_multipan_other_device(
-    hass: HomeAssistant, addon_info, addon_running
-) -> None:
-    """Test zha gets the right config."""
-    mock_integration(hass, MockModule("hassio"))
-    await async_setup_component(hass, HASSIO_DOMAIN, {})
-
-    addon_info.return_value["options"]["device"] = "/dev/not_yellow_radio"
-
-    # Setup the config entry
-    config_entry = MockConfigEntry(
-        data={},
+        data={"firmware": ApplicationType.EZSP},
         domain=DOMAIN,
         options={},
         title="Home Assistant Yellow",
+        version=1,
+        minor_version=2,
     )
     config_entry.add_to_hass(hass)
     with (
@@ -229,10 +137,12 @@ async def test_setup_entry_no_hassio(hass: HomeAssistant) -> None:
     """Test setup of a config entry without hassio."""
     # Setup the config entry
     config_entry = MockConfigEntry(
-        data={},
+        data={"firmware": ApplicationType.EZSP},
         domain=DOMAIN,
         options={},
         title="Home Assistant Yellow",
+        version=1,
+        minor_version=2,
     )
     config_entry.add_to_hass(hass)
     assert len(hass.config_entries.async_entries()) == 1
@@ -254,10 +164,12 @@ async def test_setup_entry_wrong_board(hass: HomeAssistant) -> None:
 
     # Setup the config entry
     config_entry = MockConfigEntry(
-        data={},
+        data={"firmware": ApplicationType.EZSP},
         domain=DOMAIN,
         options={},
         title="Home Assistant Yellow",
+        version=1,
+        minor_version=2,
     )
     config_entry.add_to_hass(hass)
     assert len(hass.config_entries.async_entries()) == 1
@@ -280,10 +192,12 @@ async def test_setup_entry_wait_hassio(hass: HomeAssistant) -> None:
 
     # Setup the config entry
     config_entry = MockConfigEntry(
-        data={},
+        data={"firmware": ApplicationType.EZSP},
         domain=DOMAIN,
         options={},
         title="Home Assistant Yellow",
+        version=1,
+        minor_version=2,
     )
     config_entry.add_to_hass(hass)
     with patch(
@@ -303,14 +217,15 @@ async def test_setup_entry_addon_info_fails(
     """Test setup of a config entry when fetching addon info fails."""
     mock_integration(hass, MockModule("hassio"))
     await async_setup_component(hass, HASSIO_DOMAIN, {})
-    addon_store_info.side_effect = HassioAPIError("Boom")
 
     # Setup the config entry
     config_entry = MockConfigEntry(
-        data={},
+        data={"firmware": ApplicationType.CPC},
         domain=DOMAIN,
         options={},
         title="Home Assistant Yellow",
+        version=1,
+        minor_version=2,
     )
     config_entry.add_to_hass(hass)
     with (
@@ -319,41 +234,15 @@ async def test_setup_entry_addon_info_fails(
             return_value={"board": "yellow"},
         ),
         patch(
-            "homeassistant.components.onboarding.async_is_onboarded", return_value=False
-        ),
-    ):
-        assert not await hass.config_entries.async_setup(config_entry.entry_id)
-
-    await hass.async_block_till_done()
-    assert config_entry.state is ConfigEntryState.SETUP_RETRY
-
-
-async def test_setup_entry_addon_not_running(
-    hass: HomeAssistant, addon_installed, start_addon
-) -> None:
-    """Test the addon is started if it is not running."""
-    mock_integration(hass, MockModule("hassio"))
-    await async_setup_component(hass, HASSIO_DOMAIN, {})
-
-    # Setup the config entry
-    config_entry = MockConfigEntry(
-        data={},
-        domain=DOMAIN,
-        options={},
-        title="Home Assistant Yellow",
-    )
-    config_entry.add_to_hass(hass)
-    with (
-        patch(
-            "homeassistant.components.homeassistant_yellow.get_os_info",
-            return_value={"board": "yellow"},
+            "homeassistant.components.onboarding.async_is_onboarded",
+            return_value=False,
         ),
         patch(
-            "homeassistant.components.onboarding.async_is_onboarded", return_value=False
+            "homeassistant.components.homeassistant_yellow.check_multi_pan_addon",
+            side_effect=HomeAssistantError("Boom"),
         ),
     ):
         assert not await hass.config_entries.async_setup(config_entry.entry_id)
-        await hass.async_block_till_done()
 
+    await hass.async_block_till_done()
     assert config_entry.state is ConfigEntryState.SETUP_RETRY
-    start_addon.assert_called_once()