Use local brand icons for update entities#5249
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds a local HACS HTTP endpoint for serving installed integration brand icons and updates HACS update entities to use that local endpoint (with a redirect fallback to the legacy Home Assistant Brands CDN), so update cards can display local custom_components/<domain>/brand/icon.png assets.
Changes:
- Add
HacsBrandIconViewat/api/hacs/brands/{domain}/icon.pngto serve localbrand/icon.pngfor installed integration repositories, otherwise redirect to the Brands CDN. - Update update-entity
entity_pictureto point to the new local endpoint. - Add unit tests for the view and update snapshot expectations for
entity_picture.
Reviewed changes
Copilot reviewed 44 out of 44 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| custom_components/hacs/brands.py | New HTTP view that serves local brand icons with a CDN redirect fallback. |
| custom_components/hacs/const.py | Adds constants for the local brand icon URL and CDN fallback URL. |
| custom_components/hacs/frontend.py | Registers the new brand icon HTTP view during frontend setup. |
| custom_components/hacs/update.py | Switches update entity entity_picture from CDN URL to the local endpoint. |
| tests/test_brands.py | Adds unit tests covering local serving, CDN fallback redirect, and invalid-domain handling. |
| tests/snapshots/test_integration_setup.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/theme-basic/test_update_repository_websocket.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/theme-basic/test_update_repository_entity.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/theme-basic/test_remove_repository_pre.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/theme-basic/test_remove_repository_post.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/theme-basic/test_download_repository.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/theme-basic/test_discard_invalid_repo_data.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/template-basic/test_update_repository_websocket.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/template-basic/test_update_repository_entity.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/template-basic/test_remove_repository_pre.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/template-basic/test_remove_repository_post.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/template-basic/test_download_repository.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/template-basic/test_discard_invalid_repo_data.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/python_script-basic/test_update_repository_websocket.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/python_script-basic/test_update_repository_entity.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/python_script-basic/test_remove_repository_pre.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/python_script-basic/test_remove_repository_post.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/python_script-basic/test_download_repository.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/python_script-basic/test_discard_invalid_repo_data.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/plugin-basic/test_update_repository_websocket.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/plugin-basic/test_update_repository_entity.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/plugin-basic/test_remove_repository_pre.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/plugin-basic/test_remove_repository_post.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/plugin-basic/test_download_repository.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/plugin-basic/test_discard_invalid_repo_data.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/integration-basic/test_update_repository_websocket.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/integration-basic/test_update_repository_entity.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/integration-basic/test_update_entity_state.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/integration-basic/test_switch/entity_states.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/integration-basic/test_remove_repository_pre.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/integration-basic/test_remove_repository_post.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/integration-basic/test_download_repository.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/integration-basic/test_discard_invalid_repo_data.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/appdaemon-basic/test_update_repository_websocket.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/appdaemon-basic/test_update_repository_entity.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/appdaemon-basic/test_remove_repository_pre.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/appdaemon-basic/test_remove_repository_post.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/appdaemon-basic/test_download_repository.json | Updates snapshot entity_picture to the new local endpoint. |
| tests/snapshots/hacs-test-org/appdaemon-basic/test_discard_invalid_repo_data.json | Updates snapshot entity_picture to the new local endpoint. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| name = "api:hacs:brand_icon" | ||
| url = BRAND_ICON_URL | ||
| requires_auth = False |
| if not path.is_file(): | ||
| return None | ||
| return path.read_bytes() | ||
|
|
||
|
|
|
Closing this as a duplicate after finding the existing issue/PR chain for the same HA 2026.3 brands-proxy migration: #5223 and #5228. The Asmoke Cloud case is the same symptom: local custom integration brand assets are present, but the HACS-created update entity still points at the legacy Brands CDN placeholder. |
Summary
brand/icon.pngwhen present and redirect to the existing Brands CDN fallback when it is not.Motivation
Home Assistant Brands no longer accepts new brand icons for custom integrations since the 2026.3 local branding changes. HACS validation already accepts local
custom_components/<domain>/brand/icon.pngassets, but update entities still hardcodehttps://brands.home-assistant.io/_/{domain}/icon.png. That means HACS update cards can show the placeholder icon for valid custom integrations that ship local brand assets.I first considered the Home Assistant Brands Proxy API, but this keeps HACS compatible with older supported Home Assistant versions while still allowing installed local brand assets to show in the update entity.
Tests
.venv313/bin/python -m ruff check custom_components/hacs/brands.py custom_components/hacs/const.py custom_components/hacs/frontend.py custom_components/hacs/update.py tests/test_brands.py.venv313/bin/python -m pytest tests/test_brands.py tests/test_update.py tests/test_switch.py -q