Skip to content
Merged
Show file tree
Hide file tree
Changes from 138 commits
Commits
Show all changes
146 commits
Select commit Hold shift + click to select a range
c96d5dc
Add WiiM media player integration
WiimHome Jul 17, 2025
e2cebf3
Merge branch 'dev' into feature/wiim-integration
Linkplay2020 Jul 18, 2025
56b3eb1
Merge branch 'dev' into feature/wiim-integration
Linkplay2020 Jul 18, 2025
f6858d2
Merge branch 'dev' into feature/wiim-integration
Linkplay2020 Jul 21, 2025
66b11e4
Merge branch 'dev' into feature/wiim-integration
Linkplay2020 Jul 21, 2025
8439541
Merge branch 'dev' into feature/wiim-integration
Linkplay2020 Jul 22, 2025
79ef189
Merge branch 'dev' into feature/wiim-integration
Linkplay2020 Jul 23, 2025
879843c
Merge branch 'dev' into feature/wiim-integration
Linkplay2020 Jul 28, 2025
7b76d8d
Merge branch 'home-assistant:dev' into feature/wiim-integration
Linkplay2020 Sep 28, 2025
644c421
Add button translation and homeassistant audio support
WiimHome Sep 29, 2025
cb233bf
Merge branch 'home-assistant:dev' into feature/wiim-integration
Linkplay2020 Sep 29, 2025
b9fc4f9
Merge branch 'dev' into feature/wiim-integration
WiimHome Nov 11, 2025
263a7cc
Fix CI check error
WiimHome Nov 11, 2025
4a4e053
For PR first version
WiimHome Nov 12, 2025
c58f679
Merge branch 'dev' into feature/wiim-integration
Linkplay2020 Nov 12, 2025
818b69e
Fix some issues from the code review
WiimHome Dec 5, 2025
529c7d4
Merge branch 'dev' into feature/wiim-integration
Linkplay2020 Dec 5, 2025
34bc01d
Merge branch 'dev' into feature/wiim-integration
Linkplay2020 Dec 23, 2025
0ce9899
Fix protected variable and other review issues
WiimHome Dec 25, 2025
d5ceb37
Remove code that is not needed for review
WiimHome Jan 12, 2026
5a78331
Move some UPnP parsing from the HA layer to the library
WiimHome Jan 28, 2026
9edf8be
Update homeassistant/components/wiim/__init__.py
Linkplay2020 Feb 24, 2026
68366d2
Update homeassistant/components/wiim/__init__.py
Linkplay2020 Feb 24, 2026
829ac69
Update homeassistant/components/wiim/__init__.py
Linkplay2020 Feb 24, 2026
ec724f1
Update homeassistant/components/wiim/__init__.py
Linkplay2020 Feb 24, 2026
b4414f2
Update homeassistant/components/wiim/__init__.py
Linkplay2020 Feb 24, 2026
fa3cfab
Update homeassistant/components/wiim/__init__.py
Linkplay2020 Feb 24, 2026
800353e
Update homeassistant/components/wiim/__init__.py
Linkplay2020 Feb 24, 2026
2e4ddce
Update homeassistant/components/wiim/__init__.py
Linkplay2020 Feb 24, 2026
71a389f
Update homeassistant/components/wiim/__init__.py
Linkplay2020 Feb 24, 2026
4e00376
Update homeassistant/components/wiim/__init__.py
Linkplay2020 Feb 24, 2026
8b96e36
Update homeassistant/components/wiim/__init__.py
Linkplay2020 Feb 24, 2026
224599d
Update homeassistant/components/wiim/__init__.py
Linkplay2020 Feb 24, 2026
c260139
Update homeassistant/components/wiim/__init__.py
Linkplay2020 Feb 24, 2026
5d74b6e
Update homeassistant/components/wiim/config_flow.py
Linkplay2020 Feb 24, 2026
f844755
Update homeassistant/components/wiim/config_flow.py
Linkplay2020 Feb 24, 2026
307b131
Update homeassistant/components/wiim/config_flow.py
Linkplay2020 Feb 24, 2026
9d5642a
Update homeassistant/components/wiim/config_flow.py
Linkplay2020 Feb 24, 2026
152bebd
Update homeassistant/components/wiim/config_flow.py
Linkplay2020 Feb 24, 2026
b88adab
Update homeassistant/components/wiim/config_flow.py
Linkplay2020 Feb 24, 2026
4ba50a8
Update homeassistant/components/wiim/config_flow.py
Linkplay2020 Feb 24, 2026
d105685
Applied review suggestions to optimize code structure and quality
WiimHome Feb 25, 2026
bd43490
Update tests/components/wiim/test_init.py
Linkplay2020 Feb 25, 2026
c9d0fdd
Update homeassistant/components/wiim/media_player.py
Linkplay2020 Feb 25, 2026
debfd44
Update homeassistant/components/wiim/config_flow.py
Linkplay2020 Feb 25, 2026
04f1f29
Update homeassistant/components/wiim/config_flow.py
Linkplay2020 Feb 25, 2026
1db9d7e
Update homeassistant/components/wiim/media_player.py
Linkplay2020 Feb 25, 2026
97ceee0
Update homeassistant/components/wiim/quality_scale.yaml
Linkplay2020 Feb 25, 2026
6866753
Unify function naming
WiimHome Feb 25, 2026
b91d8b7
Update homeassistant/components/wiim/quality_scale.yaml
Linkplay2020 Feb 25, 2026
3630fb1
Add None check
WiimHome Feb 25, 2026
9726a48
prevent frequent requests and directly raise an error on creation fai…
WiimHome Feb 26, 2026
d050c42
Update homeassistant/components/wiim/entity.py
Linkplay2020 Feb 26, 2026
5db4e1d
Update tests/components/wiim/test_init.py
Linkplay2020 Feb 26, 2026
220b2f0
Update homeassistant/components/wiim/media_player.py
Linkplay2020 Feb 26, 2026
249ebff
Update homeassistant/components/wiim/config_flow.py
Linkplay2020 Feb 26, 2026
a65dcc2
Update tests/components/wiim/test_media_player.py
Linkplay2020 Feb 26, 2026
2dee4c4
Update homeassistant/components/wiim/media_player.py
Linkplay2020 Feb 26, 2026
392e79d
Fixed issues pointed out by Copilot
WiimHome Feb 26, 2026
7149183
Update homeassistant/components/wiim/media_player.py
Linkplay2020 Feb 26, 2026
9ce2e50
Update homeassistant/components/wiim/media_player.py
Linkplay2020 Feb 26, 2026
ca55cb7
Update homeassistant/components/wiim/media_player.py
Linkplay2020 Feb 26, 2026
a0605c7
Fixed issues with logging and variable usage
WiimHome Feb 26, 2026
f04edec
Update homeassistant/components/wiim/__init__.py
Linkplay2020 Feb 26, 2026
a9a4aab
Update homeassistant/components/wiim/media_player.py
Linkplay2020 Feb 26, 2026
d8bfcea
Update homeassistant/components/wiim/media_player.py
Linkplay2020 Feb 26, 2026
8d4c253
Update homeassistant/components/wiim/media_player.py
Linkplay2020 Feb 26, 2026
b30df25
Update homeassistant/components/wiim/media_player.py
Linkplay2020 Feb 26, 2026
437be2d
Update tests/components/wiim/test_media_player.py
Linkplay2020 Feb 26, 2026
99ad8fe
Update tests/components/wiim/test_init.py
Linkplay2020 Feb 26, 2026
a78155f
Update tests/components/wiim/test_config_flow.py
Linkplay2020 Feb 26, 2026
ced0fc6
Update tests/components/wiim/test_entity.py
Linkplay2020 Feb 26, 2026
8f11167
Fixed parts of the handling logic and added additional test coverage
WiimHome Feb 27, 2026
b6f70d4
Update homeassistant/components/wiim/media_player.py
Linkplay2020 Feb 27, 2026
b279909
Update homeassistant/components/wiim/config_flow.py
Linkplay2020 Feb 27, 2026
53b17ff
Update homeassistant/components/wiim/const.py
Linkplay2020 Feb 27, 2026
85c8564
Update homeassistant/components/wiim/const.py
Linkplay2020 Feb 27, 2026
797f26f
Update homeassistant/components/wiim/const.py
Linkplay2020 Feb 27, 2026
364b068
Update homeassistant/components/wiim/__init__.py
Linkplay2020 Feb 27, 2026
f85ad64
Update homeassistant/components/wiim/media_player.py
Linkplay2020 Feb 27, 2026
b17ca64
Removed unnecessary definitions and renamed variables
WiimHome Feb 27, 2026
60de76f
Update homeassistant/components/wiim/entity.py
Linkplay2020 Feb 27, 2026
83498f6
Update tests/components/wiim/test_media_player.py
Linkplay2020 Feb 27, 2026
2ee2d40
Update tests/components/wiim/test_init.py
Linkplay2020 Feb 27, 2026
ba3f6f5
Fixed some of Copilot's suggestions
WiimHome Feb 27, 2026
269cda7
improved preset playback validation
WiimHome Feb 27, 2026
6cdf398
Refactor wiim integration around library helpers
balloob Mar 10, 2026
d455587
Remove generated wiim translation artifact
balloob Mar 10, 2026
9f80815
Inline wiim setup not-ready handling
balloob Mar 10, 2026
809a711
Clean up wiim setup entry and typed domain data
balloob Mar 10, 2026
7067ba1
Tighten wiim config flow validation
balloob Mar 10, 2026
d14ffda
Refine wiim media player command handling
balloob Mar 10, 2026
006bd97
Remove wiim host and location ambiguity
balloob Mar 10, 2026
30c4549
Clarify wiim config flow host probing
balloob Mar 10, 2026
c70f06a
Always refresh wiim media player state
balloob Mar 10, 2026
89f15e1
More cleanup
balloob Mar 10, 2026
5284c80
Refine wiim media player state handling
balloob Mar 11, 2026
97f633c
Simplify wiim leader entity handling
balloob Mar 11, 2026
87b1b3e
Use wiim devices for grouped playback routing
balloob Mar 11, 2026
2911159
Simplify wiim metadata device handling
balloob Mar 11, 2026
a0f05f6
Assert wiim controller device lookups
balloob Mar 11, 2026
7ae6db9
Drop dead wiim output mode guard
balloob Mar 11, 2026
0100cd6
Remove dead wiim play mode handling
balloob Mar 11, 2026
c25ce9e
Rename wiim supported feature scheduler
balloob Mar 11, 2026
43d78c9
Rely on strict wiim controller lookups
balloob Mar 11, 2026
4ab2bad
Merge pull request #1 from balloob-travel/codex/pr-148948-gh
Linkplay2020 Mar 12, 2026
de4129d
Update WiiM SDK version
WiimHome Mar 12, 2026
7c2adf8
Fix mypy and progress bar synchronization issues
WiimHome Mar 12, 2026
9c62ffc
Merge branch 'dev' into feature/wiim-integration
Linkplay2020 Mar 12, 2026
8604a44
Fix progress bar update issue caused by refresh timing
WiimHome Mar 13, 2026
3c74bac
Address comments 1
balloob Mar 13, 2026
6be7afa
Remove added to hass
balloob Mar 13, 2026
62f32f8
Fix wiim cleanup follow-up issues
balloob Mar 13, 2026
7526985
Register wiim event callbacks after setup
balloob Mar 13, 2026
479728e
Cache wiim transport capabilities
balloob Mar 13, 2026
543d58b
Drop dead wiim scheduler hass guard
balloob Mar 13, 2026
59663fb
Format
balloob Mar 13, 2026
9ba70a5
Merge pull request #2 from balloob-travel/feature/wiim-integration
Linkplay2020 Mar 13, 2026
9dcf973
Merge branch 'dev' into feature/wiim-integration
Linkplay2020 Mar 13, 2026
3743c8c
Merge branch 'dev' into feature/wiim-integration
Linkplay2020 Mar 13, 2026
1ce527d
Format code and fix device online/offline handling
WiimHome Mar 14, 2026
1ba8a20
Remove unnecessary asyncio
WiimHome Mar 14, 2026
ed70ee6
Merge branch 'dev' into feature/wiim-integration
Linkplay2020 Mar 14, 2026
661ae29
Update the library version to 0.1.0
WiimHome Mar 14, 2026
70122e3
Refine WiiM setup and config flow errors
balloob Mar 15, 2026
9afe43a
Use public WiiM device metadata in entities
balloob Mar 15, 2026
28f953a
Remove WiiM sound mode media player support
balloob Mar 15, 2026
3b26333
Tighten remaining WiiM media player follow-ups
balloob Mar 15, 2026
1b34058
Update WiiM code owners
balloob Mar 15, 2026
228d148
More changes
balloob Mar 15, 2026
50be3cd
Merge pull request #3 from balloob-travel/codex/wiim-review-followups-v2
Linkplay2020 Mar 16, 2026
e61b088
Fix mypy and prek checks
WiimHome Mar 16, 2026
0419ec6
Full code test coverage
WiimHome Mar 16, 2026
0a74562
Refine WiiM config flow tests
balloob Mar 16, 2026
5342725
Refactor WiiM media player tests
balloob Mar 17, 2026
2119294
Adjust WiiM tests after rebase
balloob Mar 17, 2026
b50fa42
Merge pull request #4 from balloob-travel/codex/wiim-configflow-follo…
Linkplay2020 Mar 17, 2026
f40cb75
Merge branch 'dev' into feature/wiim-integration
Linkplay2020 Mar 17, 2026
9e6da69
Handle WiiM grouped media commands
balloob Mar 17, 2026
c1a2f33
Merge pull request #5 from balloob-travel/feature/wiim-integration
Linkplay2020 Mar 17, 2026
7988c4d
Patch wiim config flow probe tests
balloob Mar 18, 2026
287a649
Merge pull request #6 from balloob-travel/feature/wiim-integration
Linkplay2020 Mar 18, 2026
637ac7c
Merge branch 'dev' into feature/wiim-integration
joostlek Mar 18, 2026
b0220c4
Fix
joostlek Mar 18, 2026
e78036a
Fix
joostlek Mar 18, 2026
99a0424
Fix
joostlek Mar 18, 2026
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
2 changes: 2 additions & 0 deletions CODEOWNERS

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

128 changes: 128 additions & 0 deletions homeassistant/components/wiim/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
"""The WiiM integration."""

from __future__ import annotations

from typing import TYPE_CHECKING
from urllib.parse import urlparse

from wiim.controller import WiimController
from wiim.discovery import async_create_wiim_device
from wiim.exceptions import WiimDeviceException, WiimRequestException

from homeassistant.const import CONF_HOST, EVENT_HOMEASSISTANT_STOP
from homeassistant.core import Event, HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.network import NoURLAvailableError, get_url

from .const import DATA_WIIM, DOMAIN, LOGGER, PLATFORMS, UPNP_PORT, WiimConfigEntry
from .models import WiimData

DEFAULT_AVAILABILITY_POLLING_INTERVAL = 60


async def async_setup_entry(hass: HomeAssistant, entry: WiimConfigEntry) -> bool:
"""Set up WiiM from a config entry.

This method owns the device connect/disconnect lifecycle.
"""
LOGGER.debug(
"Setting up WiiM entry: %s (UDN: %s, Source: %s)",
entry.title,
entry.unique_id,
entry.source,
)

# This integration maintains shared domain-level state because:
# - Multiple config entries can be loaded simultaneously.
# - All WiiM devices share a single WiimController instance
# to coordinate network communication and event handling.
# - We also maintain a global entity_id -> UDN mapping
# used for cross-entity event routing.
#
# The domain data must therefore be initialized once and reused
# across all config entries.
session = async_get_clientsession(hass)

if DATA_WIIM not in hass.data:
hass.data[DATA_WIIM] = WiimData(controller=WiimController(session))

wiim_domain_data = hass.data[DATA_WIIM]
controller = wiim_domain_data.controller

host = entry.data[CONF_HOST]
upnp_location = f"http://{host}:{UPNP_PORT}/description.xml"

try:
base_url = get_url(hass, prefer_external=False)
except NoURLAvailableError as err:
raise ConfigEntryNotReady("Failed to determine Home Assistant URL") from err

local_host = urlparse(base_url).hostname
if TYPE_CHECKING:
assert local_host is not None

Comment on lines +61 to +64
try:
wiim_device = await async_create_wiim_device(
upnp_location,
session,
host=host,
local_host=local_host,
polling_interval=DEFAULT_AVAILABILITY_POLLING_INTERVAL,
)
except WiimRequestException as err:
raise ConfigEntryNotReady(f"HTTP API request failed for {host}: {err}") from err
except WiimDeviceException as err:
raise ConfigEntryNotReady(f"Device setup failed for {host}: {err}") from err

await controller.add_device(wiim_device)

entry.runtime_data = wiim_device
LOGGER.info(
"WiiM device %s (UDN: %s) linked to HASS. Name: '%s', HTTP: %s, UPnP Location: %s",
entry.entry_id,
wiim_device.udn,
wiim_device.name,
host,
Comment on lines +81 to +86
upnp_location or "N/A",
)

async def _async_shutdown_event_handler(event: Event) -> None:
LOGGER.info(
"Home Assistant stopping, disconnecting WiiM device: %s",
wiim_device.name,
)
await wiim_device.disconnect()

entry.async_on_unload(
hass.bus.async_listen_once(
EVENT_HOMEASSISTANT_STOP, _async_shutdown_event_handler
)
)

async def _unload_entry_cleanup():
"""Cleanup when unloading the config entry.

Removes the device from the controller and disconnects it.
"""
LOGGER.debug("Running unload cleanup for %s", wiim_device.name)
await controller.remove_device(wiim_device.udn)
await wiim_device.disconnect()

entry.async_on_unload(_unload_entry_cleanup)
Comment on lines +103 to +112
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

entry.async_on_unload(_unload_entry_cleanup) registers an async function; unload callbacks are called synchronously, so this will likely create an un-awaited coroutine and skip cleanup (device removal/disconnect). Move this cleanup into async_unload_entry (awaited), or register a sync callback that schedules the coroutine with hass.async_create_task.

Copilot uses AI. Check for mistakes.
Comment on lines +103 to +112
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

entry.async_on_unload(...) expects a synchronous callback/unsubscriber; passing an async function means it will be called without awaiting, so the device removal/disconnect may never run (and can also trigger 'coroutine was never awaited' warnings). Move this cleanup into async_unload_entry, or register a sync wrapper that schedules the coroutine with hass.async_create_task(...).

Copilot uses AI. Check for mistakes.

await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
return True


async def async_unload_entry(hass: HomeAssistant, entry: WiimConfigEntry) -> bool:
"""Unload a config entry."""
LOGGER.info("Unloading WiiM entry: %s (UDN: %s)", entry.title, entry.unique_id)

if not await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
return False

if not hass.config_entries.async_loaded_entries(DOMAIN):
hass.data.pop(DATA_WIIM)
LOGGER.info("Last WiiM entry unloaded, cleaning up domain data")
return True
132 changes: 132 additions & 0 deletions homeassistant/components/wiim/config_flow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
"""Config flow for WiiM integration."""

from __future__ import annotations

from typing import Any

import voluptuous as vol
from wiim.discovery import async_probe_wiim_device
from wiim.models import WiimProbeResult

from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
from homeassistant.const import CONF_HOST
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.service_info.zeroconf import ZeroconfServiceInfo

from .const import DOMAIN, LOGGER, UPNP_PORT

STEP_USER_DATA_SCHEMA = vol.Schema({vol.Required(CONF_HOST): str})


async def _async_probe_wiim_host(hass: HomeAssistant, host: str) -> WiimProbeResult:
"""Probe the given host and return WiiM device information."""
session = async_get_clientsession(hass)
location = f"http://{host}:{UPNP_PORT}/description.xml"
LOGGER.debug("Validating UPnP device at location: %s", location)
try:
probe_result = await async_probe_wiim_device(
location,
session,
host=host,
)
except TimeoutError as err:
raise CannotConnect from err

if probe_result is None:
raise CannotConnect
return probe_result
Comment on lines +23 to +39


class WiimConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for WiiM."""

_discovered_info: WiimProbeResult | None = None
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't assign it here, just make it a type annotation:

Suggested change
_discovered_info: WiimProbeResult | None = None
_discovered_info: WiimProbeResult


Comment on lines +42 to +46
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WiimConfigFlow is missing VERSION = 1 (and typically MINOR_VERSION = 1) class attributes that are present in most config flows to support future migrations. Add these to the flow class so config entries can be migrated safely when the schema changes.

Copilot uses AI. Check for mistakes.
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle the initial step when user adds integration manually."""
errors: dict[str, str] = {}
if user_input is not None:
host = user_input[CONF_HOST]
try:
device_info = await _async_probe_wiim_host(self.hass, host)
except CannotConnect:
errors["base"] = "cannot_connect"
else:
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When an unexpected exception occurs on line 108-115, the code both logs the error with errors["base"] = "unknown" AND re-raises the exception with raise. This will cause the exception to propagate and prevent the form from being shown to the user with the error message. Either remove the raise statement to show the form with the error, or remove the error assignment if the exception should propagate.

Suggested change
else:

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is recommended to keep this else.

await self.async_set_unique_id(device_info.udn)
self._abort_if_unique_id_configured()
return self.async_create_entry(
title=device_info.name,
data={
CONF_HOST: device_info.host,
},
)

return self.async_show_form(
step_id="user",
data_schema=self.add_suggested_values_to_schema(
STEP_USER_DATA_SCHEMA, user_input
),
errors=errors,
)

async def async_step_zeroconf(
self, discovery_info: ZeroconfServiceInfo
) -> ConfigFlowResult:
"""Handle Zeroconf discovery."""
LOGGER.debug(
"Zeroconf discovery received: Name: %s, Host: %s, Port: %s, Properties: %s",
discovery_info.name,
discovery_info.host,
discovery_info.port,
discovery_info.properties,
)

host = discovery_info.host
udn_from_txt = discovery_info.properties.get("uuid")
if udn_from_txt:
await self.async_set_unique_id(udn_from_txt)
self._abort_if_unique_id_configured(updates={CONF_HOST: host})

try:
device_info = await _async_probe_wiim_host(self.hass, host)
except CannotConnect:
return self.async_abort(reason="cannot_connect")

await self.async_set_unique_id(device_info.udn)
self._abort_if_unique_id_configured(updates={CONF_HOST: device_info.host})

self._discovered_info = device_info
self.context["title_placeholders"] = {"name": device_info.name}
return await self.async_step_discovery_confirm()

async def async_step_discovery_confirm(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle user confirmation of discovered device."""
discovered_info = self._discovered_info
if user_input is not None and discovered_info is not None:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

discovered_info can't be None

return self.async_create_entry(
title=discovered_info.name,
data={
CONF_HOST: discovered_info.host,
},
)

return self.async_show_form(
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commented-out code should be removed. Line 233 contains a commented-out call to _set_confirm_only() that should either be uncommented if needed or removed entirely.

Suggested change
return self.async_show_form(

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The commented-out _set_confirm_only() call has been removed to clean up the code.

step_id="discovery_confirm",
description_placeholders={
"name": (
discovered_info.name
if discovered_info is not None
else "Discovered WiiM Device"
)
},
)


class CannotConnect(HomeAssistantError):
"""Error to indicate we cannot connect."""
27 changes: 27 additions & 0 deletions homeassistant/components/wiim/const.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"""Constants for the WiiM integration."""

import logging
from typing import TYPE_CHECKING, Final

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.util.hass_dict import HassKey

if TYPE_CHECKING:
from wiim import WiimDevice

from .models import WiimData

type WiimConfigEntry = ConfigEntry[WiimDevice]

DOMAIN: Final = "wiim"
LOGGER = logging.getLogger(__package__)
DATA_WIIM: HassKey[WiimData] = HassKey(DOMAIN)

PLATFORMS: Final[list[Platform]] = [
Platform.MEDIA_PLAYER,
]

UPNP_PORT = 49152

ZEROCONF_TYPE_LINKPLAY: Final = "_linkplay._tcp.local."
36 changes: 36 additions & 0 deletions homeassistant/components/wiim/entity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""Base entity for the WiiM integration."""

from __future__ import annotations

from wiim.wiim_device import WiimDevice

from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.entity import Entity

from .const import DOMAIN


class WiimBaseEntity(Entity):
"""Base representation of a WiiM entity."""

_attr_has_entity_name = True

def __init__(self, wiim_device: WiimDevice) -> None:
"""Initialize the WiiM base entity."""
self._device = wiim_device
self._attr_device_info = dr.DeviceInfo(
identifiers={(DOMAIN, self._device.udn)},
name=self._device.name,
manufacturer=self._device.manufacturer,
model=self._device.model_name,
sw_version=self._device.firmware_version,
)
if self._device.presentation_url:
self._attr_device_info["configuration_url"] = self._device.presentation_url
elif self._device.http_api_url:
self._attr_device_info["configuration_url"] = self._device.http_api_url

@property
def available(self) -> bool:
"""Return True if entity is available."""
return self._device.available
13 changes: 13 additions & 0 deletions homeassistant/components/wiim/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"domain": "wiim",
"name": "WiiM",
"codeowners": ["@Linkplay2020"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/wiim",
"integration_type": "hub",
"iot_class": "local_push",
"loggers": ["wiim.sdk", "async_upnp_client"],
"quality_scale": "bronze",
"requirements": ["wiim==0.1.0"],
"zeroconf": ["_linkplay._tcp.local."]
}
Loading