Normalize unique ID in WLED
Breaking change
Proposed change
Close: https://github.com/home-assistant/core/issues/157879
We recently started using unique IDs to verify that we were connecting to the correct device. However, it turned out that some users had their unique IDs set to uppercase. I'm not sure how this could have happened, as WLED always returns lowercase letters, but this prevented them from using this integration.
This PR normalizes WLED MAC addresses to lowercase to fix the issue. It adds a migration from version 1.1 to 1.2 that normalizes existing unique IDs and handles duplicate entries during the migration process.
Key changes:
- Adds normalize_mac_address() function to convert MAC addresses to lowercase and remove separators
- Implements config entry migration from version 1.1 to 1.2 to normalize existing unique IDs
- Applies normalization consistently in config flows and coordinator MAC address comparisons
Type of change
- [ ] Dependency upgrade
- [X] Bugfix (non-breaking change which fixes an issue)
- [ ] New integration (thank you!)
- [ ] New feature (which adds functionality to an existing integration)
- [ ] Deprecation (breaking change to happen in the future)
- [ ] Breaking change (fix/feature causing existing functionality to break)
- [ ] Code quality improvements to existing code or addition of tests
Additional information
- This PR fixes or closes issue: fixes Close #157879
- This PR is related to issue:
- Link to documentation pull request:
- Link to developer documentation pull request:
- Link to frontend pull request:
Checklist
- [X] I understand the code I am submitting and can explain how it works.
- [X] The code change is tested and works locally.
- [X] Local tests pass. Your PR cannot be merged unless tests pass
- [X] There is no commented out code in this PR.
- [ ] I have followed the development checklist
- [ ] I have followed the perfect PR recommendations
- [ ] The code has been formatted using Ruff (
ruff format homeassistant tests) - [ ] Tests have been added to verify that the new code works.
- [ ] Any generated code has been carefully reviewed for correctness and compliance with project standards.
If user exposed functionality or configuration variables are added/changed:
- [ ] Documentation added/updated for www.home-assistant.io
If the code communicates with devices, web services, or third-party tools:
- [ ] The manifest file has all fields filled out correctly.
Updated and included derived files by running:python3 -m script.hassfest. - [ ] New or updated dependencies have been added to
requirements_all.txt.
Updated by runningpython3 -m script.gen_requirements_all. - [ ] For the updated dependencies - a link to the changelog, or at minimum a diff between library versions is added to the PR description.
To help with the load of incoming pull requests:
- [ ] I have reviewed two other open pull requests in this repository.
Hey there @frenck, mind taking a look at this pull request as it has been labeled with an integration (wled) you are listed as a code owner for? Thanks!
Code owner commands
Code owners of wled can trigger bot actions by commenting:
-
@home-assistant closeCloses the pull request. -
@home-assistant rename Awesome new titleRenames the pull request. -
@home-assistant reopenReopen the pull request. -
@home-assistant unassign wledRemoves the current integration label and assignees on the pull request, add the integration domain after the command. -
@home-assistant add-label needs-more-informationAdd a label (needs-more-information, problem in dependency, problem in custom component) to the pull request. -
@home-assistant remove-label needs-more-informationRemove a label (needs-more-information, problem in dependency, problem in custom component) on the pull request.
- In the case where the duplicate config entry is ignored, the WLED integration is able to connect to the device with no repairs and no user interactions.
- When I stopped ignoring the duplicate integration, after a restart it went away entirely from the config registry.
This means I didn't test the repair workflow, but I'd say the PR as is fixes the issues I encountered well. Thanks!
Please take a look at the requested changes, and use the Ready for review button when you are done, thanks :+1:
I would say let's bump the minor version of the config entry and implement such thing in the migration of the entry.
I thought about it, but it wouldn't allow us to handle conflicts because the migration can only be run once. Here this code needs to be run multiple times until the user fixes all the conflicts. I could just set a unique ID without checking for duplicates, but that will stop working in 2025.11. https://github.com/home-assistant/core/blob/d2c3543b6cb4237f8fe1ec700b205d7699edca0b/homeassistant/config_entries.py#L2799
Do we have any reason to believe people have duplicate entries?
Yes. Users in the discussion reported that they had duplicates because Zeroconf/DHCP discovery was likely creating entries with the wrong MAC address. and they created their entries manually and had duplicates, but that's just speculation, as I haven't been able to confirm this with certainty. I only saw that WLED always returned lowercase letters, and Discovery is another source for the MAC address, and I saw that it wasn't normalized.
Here is normalization in WLED: https://github.com/wled/WLED/blob/cc5b5047719668b4e36d9ba70e8cf7896c3b9471/wled00/wled.cpp#L441-L444 https://github.com/wled/WLED/blob/cc5b5047719668b4e36d9ba70e8cf7896c3b9471/wled00/json.cpp#L886
An alternative is to completely drop the unique ID repair, because when we compare the MAC address, we normalize it anyway. It's not a big deal if someone created a config entry and has the unique ID in the wrong format, because now the integration will still work.
What about entity unique ids?
This shouldn't cause a problem as they are always set based on the values from the WLED API. https://github.com/home-assistant/core/blob/845c9ee05fd2b262e9f4ba29ef62babc6499b4f7/homeassistant/components/wled/sensor.py#L157
Hmm, okay. So I am thinking a few things:
- It's a little mess at the moment
- I think if people have an entry both set up and ignored, we can delete the ignored one.
- Disabled config entries don't get migrated I believe
- If users had the integration set up twice, it would be in a faulty state as it would register unique ids twice.
- What do we use for the device identifiers? I would assume it also exposes the mac and thus merges with the other one.
I don't have a definitive answer just yet, but I think we can do without notifying the user.
@joostlek I added a migration that deletes ignored entries and then updates the entries to normalize the unique ID. We don't have repairs, but if the migration fails, we have a message why it failed in the log.
What do we use for the device identifiers? I would assume it also exposes the mac and thus merges with the other one.
Yes, we use the MAC address for device identifiers. This is exactly why validating the MAC address during connection was important. Without that validation, a config entry created for one device could be matched to a different device. Later, when DHCP Discovery updated the entry, we ended up with one physical device having two config entries. One of them had zero entities, while the other contained all the correct ones.
This is what it looks like.
Since we now validate the MAC address during the connection step, we should no longer run into this issue.
I still need to clean up my own HA instances and remove the empty devices, but that's a separate topic. It isn’t a big problem for me right now. Fixing it wouldn’t be trivial anyway, because it would likely require reconfiguring the WLED integration, which also means reentering the segment names from the device into HA. In the future, I want to improve this so that segment names are copied automatically, which should make this process much easier.
Any ETA on when this will go out? I've had LED strips that I haven't been able to control for the past 4 days since this issue appeared.
@altShiftDev Does deleting and re-adding the device solve the problem? Can you verify this?
We don't have an ETA, but we're working hard on it.
@altShiftDev Does deleting and re-adding the device solve the problem? Can you verify this?
It likely would but it would also remove those entities from all scenes and automations. That's quite disruptive and I'd like to avoid doing so if this fix is around the corner.
I can confirm that the right-click menu "reconfigure" does unfortunately not "reconfigure" anything but the IP address and gets tripped up at the mac address comparison. It would be extremely helpful to allow both IP and Mac address reconfiguring to avoid these lockouts in the future. I see no reason this can't be exposed to the user.
It would be extremely helpful to allow both IP and Mac address reconfiguring to avoid these lockouts in the future. I see no reason this can't be exposed to the user.
Allowing users to edit the MAC address isn’t a good idea because the MAC is used as the unique_id for the config entry and as the primary device identifier in Home Assistant. Changing it would break the link between the entry, the device registry and all related entities, potentially creating duplicates, collisions or orphaned entities.
It would also recreate the exact problems previous PR was designed to prevent. The original bug was that HA could accidentally associate a WLED entry with the wrong physical device when only the host/IP changed. This sometimes caused a single device to be linked to multiple config entries or made entities appear under the wrong controller. That is why explicit MAC verification was added in the first place: https://github.com/home-assistant/core/pull/155491
Letting the MAC be user-editable would effectively disable that protection and open the door to the same class of issues again.
Respectfully I disagree.
Allowing the power users to edit the MAC is a better idea than doing a blind string comparison without first sanitizing your inputs. It also allows users to fix their own issues instead of waiting on hotfixes when things break again in the future.
Allowing explicit MAC verification is fine, enforcing it without bulletproof sanitizing of formats like uppercase/lowercase with and without colons is not fine.
Letting the MAC be user-editable would effectively disable that protection and open the door to the same class of issues again.
There's no reason why allowing user-editable MAC addresses would recreate the past bug you're describing. I'm not saying to rollback the past protections, I'm asking you to allow power users to fix their own issues when things go wrong.
If you need the change sooner, you can override the integration locally. Home Assistant supports loading a core integration as a custom component:
- Copy the
wledfolder fromhomeassistant/components/wledinto<config>/custom_components/wled. - Add a
"version"field with a dummy value (for example"0.0.0") to themanifest.jsonfile. - Apply whatever modifications you want, including making the MAC editable, or cherry-pick this PR.
- Restart Home Assistant so your custom version is used instead of the core one.
Alternatively, you can stay on the previous Home Assistant version that didn’t yet include MAC validation and wait until the fix is released. Both approaches let you continue using the setup you prefer while the upstream review runs its course.
1. Copy the `wled` folder from `homeassistant/components/wled` into `<config>/custom_components/wled`.
Alternatively, you can stay on the previous Home Assistant version that didn’t yet include MAC validation and wait until the fix is released. Both approaches let you continue using the setup you prefer while the upstream review runs its course.
This folder doesn't exist, not sure if it's because I'm on the docker version or something else.
It would be great if you accelerated this PR given it's broken the HA wled functionality for at least a few users.
Here is folder with WLED component: https://github.com/home-assistant/core/tree/dev/homeassistant/components/wled
For HAOS, the /config directory is accessible from Visual Studio Server or Terminal.
For plain docker, the /config directory is mounted in user-controlled volume
I'm doing my best to finish this PR, but I have to wait for the reviewers, who also have other challenges and have to divide their time between other components.