Skip to content

Add Tween Light Infrared integration#172803

Open
tr4nt0r wants to merge 2 commits into
home-assistant:devfrom
tr4nt0r:tween_light_ir
Open

Add Tween Light Infrared integration#172803
tr4nt0r wants to merge 2 commits into
home-assistant:devfrom
tr4nt0r:tween_light_ir

Conversation

@tr4nt0r
Copy link
Copy Markdown
Contributor

@tr4nt0r tr4nt0r commented Jun 2, 2026

Proposed change

Tween Light is a brand marketed by the European home improvement retail chain BAUHAUS.
This integration currently only supports the Tween Light LED Strip, which comes with a 24-key infrared remote. There are other light products, like various RGB ceiling lights and LED panels, but they use different remotes for which I don't know the IR codes (actually not sure if they are IR or RF).

This 24-key remote is a pretty wide-spread model and is sold with many different LED controllers, often cheap, no-name products, which can easily be found for example on Amazon (1, 2) or Aliexpress. So this integration should be compatible with a lot of different LED controllers.
24-key

The integration requires infrared-protocols==5.8.0

Type of change

  • Dependency upgrade
  • 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

Checklist

  • I understand the code I am submitting and can explain how it works.
  • The code change is tested and works locally.
  • Local tests pass. Your PR cannot be merged unless tests pass
  • 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:

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 running python3 -m script.gen_requirements_all.
  • For the updated dependencies a diff between library versions and ideally a link to the changelog/release notes is added to the PR description.

To help with the load of incoming pull requests:

Copy link
Copy Markdown
Contributor

@home-assistant home-assistant Bot left a comment

Choose a reason for hiding this comment

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

This PR includes a brand folder inside the component. Brand assets should not be part of the core repository. Please refer to the brand images documentation for the correct approach.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds a new tween_light_ir Home Assistant integration backed by the infrared domain, including a Light platform, config flow, translations/icons, strict typing, and tests/snapshots.

Changes:

  • Introduce the new tween_light_ir integration (manifest, init/unload, config flow, constants, light platform, base entity).
  • Add translations (strings/icons), generated integration registries, and quality scale metadata.
  • Add integration test suite (config flow, init, light behavior + snapshot) and enable strict mypy settings.

Reviewed changes

Copilot reviewed 18 out of 23 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
homeassistant/components/tween_light_ir/init.py Sets up/unloads config entries and forwards to the Light platform.
homeassistant/components/tween_light_ir/config_flow.py Adds config flow to select device type and infrared entities.
homeassistant/components/tween_light_ir/const.py Defines domain constants and device type enum.
homeassistant/components/tween_light_ir/entity.py Provides shared device info + unique_id behavior.
homeassistant/components/tween_light_ir/light.py Implements Light entity that sends Tween Light IR codes.
homeassistant/components/tween_light_ir/manifest.json Registers the integration metadata.
homeassistant/components/tween_light_ir/strings.json Adds UI strings for config flow and effect translations.
homeassistant/components/tween_light_ir/icons.json Adds entity/effect icon translations.
homeassistant/components/tween_light_ir/quality_scale.yaml Declares quality scale rule status for the integration.
homeassistant/generated/integrations.json Adds generated integration entry for tween_light_ir.
homeassistant/generated/config_flows.py Adds tween_light_ir to generated config flow list.
mypy.ini Enables strict mypy checks for homeassistant.components.tween_light_ir.*.
.strict-typing Marks tween_light_ir as strict-typing.
CODEOWNERS Assigns component and tests ownership.
tests/components/tween_light_ir/conftest.py Adds test fixtures for config entries and IR code patching.
tests/components/tween_light_ir/test_config_flow.py Tests config flow happy path, already configured, and missing IR entities.
tests/components/tween_light_ir/test_init.py Tests entry setup and unload.
tests/components/tween_light_ir/test_light.py Snapshot test + service/action tests for IR code dispatch.
tests/components/tween_light_ir/snapshots/test_light.ambr Snapshot for light entity registry/state.
tests/components/tween_light_ir/init.py Declares tests package.

Comment on lines +48 to +55
self._async_abort_entries_match(
{
CONF_DEVICE_TYPE: user_input[CONF_DEVICE_TYPE],
CONF_INFRARED_ENTITY_ID: user_input.get(
CONF_INFRARED_ENTITY_ID
),
}
)
Comment on lines +45 to +47
if user_input.get(CONF_INFRARED_ENTITY_ID) or user_input.get(
CONF_INFRARED_RECEIVER_ENTITY_ID
):
Comment on lines +56 to +59
return self.async_create_entry(
title=DEVICE_TYPE_NAMES[user_input[CONF_DEVICE_TYPE]],
data=user_input,
)
Comment on lines +30 to +31
if not (infrared_entity_id := entry.data.get(CONF_INFRARED_ENTITY_ID)):
return
Comment thread homeassistant/components/tween_light_ir/entity.py Outdated
Comment thread tests/components/tween_light_ir/test_light.py Outdated
Comment thread homeassistant/components/tween_light_ir/light.py Outdated
Copilot AI review requested due to automatic review settings June 2, 2026 01:36
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 18 out of 20 changed files in this pull request and generated 5 comments.

Comment on lines +41 to +61
if not emitter_entity_ids and not receiver_entity_ids:
return self.async_abort(reason="no_infrared_entities")

if user_input is not None:
if user_input.get(CONF_INFRARED_ENTITY_ID) or user_input.get(
CONF_INFRARED_RECEIVER_ENTITY_ID
):
self._async_abort_entries_match(
{
CONF_DEVICE_TYPE: user_input[CONF_DEVICE_TYPE],
CONF_INFRARED_ENTITY_ID: user_input.get(
CONF_INFRARED_ENTITY_ID
),
}
)
return self.async_create_entry(
title=DEVICE_TYPE_NAMES[user_input[CONF_DEVICE_TYPE]],
data=user_input,
)

errors["base"] = "missing_infrared_entity"
Comment on lines +29 to +35
"""Set up platform from config entry."""
if not (infrared_entity_id := entry.data.get(CONF_INFRARED_ENTITY_ID)):
return

device_type = entry.data[CONF_DEVICE_TYPE]
if device_type == TweenLightIrDeviceType.LED_STRIP:
async_add_entities([TweenLightIrLightEntity(entry, infrared_entity_id)])
Comment on lines +56 to +59
return self.async_create_entry(
title=DEVICE_TYPE_NAMES[user_input[CONF_DEVICE_TYPE]],
data=user_input,
)
Comment on lines +22 to +26
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, entry.entry_id)},
model=DEVICE_TYPE_NAMES[entry.data[CONF_DEVICE_TYPE]],
manufacturer="Tween Light",
)
Comment on lines +81 to +85
@pytest.mark.usefixtures("mock_infrared_emitter_entity")
async def test_user_flow_requires_emitter_or_receiver(
hass: HomeAssistant,
) -> None:
"""Test user flow requires an infrared emitter or receiver."""
Copilot AI review requested due to automatic review settings June 2, 2026 11:56
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 18 out of 20 changed files in this pull request and generated 4 comments.

Comment on lines +57 to +59
title=DEVICE_TYPE_NAMES[user_input[CONF_DEVICE_TYPE]],
data=user_input,
)
Comment on lines +45 to +55
if user_input.get(CONF_INFRARED_ENTITY_ID) or user_input.get(
CONF_INFRARED_RECEIVER_ENTITY_ID
):
self._async_abort_entries_match(
{
CONF_DEVICE_TYPE: user_input[CONF_DEVICE_TYPE],
CONF_INFRARED_ENTITY_ID: user_input.get(
CONF_INFRARED_ENTITY_ID
),
}
)
Comment on lines +77 to +86
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn device on."""
command = TweenLightLEDStripCode.ON.to_command()
self._attr_is_on = True
if ATTR_EFFECT in kwargs and kwargs[ATTR_EFFECT] in self._attr_effect_list:
effect: str = kwargs[ATTR_EFFECT]
command = TweenLightLEDStripCode[effect.upper()].to_command()

await self._send_command(command)
self.async_write_ha_state()
Comment on lines +36 to +38
CONF_DEVICE_TYPE: TweenLightIrDeviceType.LED_STRIP,
CONF_INFRARED_ENTITY_ID: EMITTER_ENTITY_ID,
CONF_INFRARED_RECEIVER_ENTITY_ID: RECEIVER_ENTITY_ID,
@joostlek
Copy link
Copy Markdown
Member

joostlek commented Jun 2, 2026

As a sidenote, I am wondering how other projects like flipper call these remotes, as like you said, I recognize these remotes and there are likely a ton of brands, and I am not sure if everyone will find it as tween light

@tr4nt0r
Copy link
Copy Markdown
Contributor Author

tr4nt0r commented Jun 2, 2026

@joostlek I found it in the Flipper DB under Generic LED_light_strip 🤷🏼. WLED has it too, they just call it 24-key.

@joostlek
Copy link
Copy Markdown
Member

joostlek commented Jun 4, 2026

Would it make sense to also call it a generic one for us?

@tr4nt0r
Copy link
Copy Markdown
Contributor Author

tr4nt0r commented Jun 5, 2026

From the WLED page, I know there are like 3 or 4 variants of this remote that use different IR codes, one of them is for Osram lamps and looks exactly the same, the others look slightly different but I don't know anything about them. I know the integration will possibly work for other controllers, too, but I can't say for which ones. The only thing I know for sure is, that it will work for the Tween Light LED strip controllers.

@joostlek
Copy link
Copy Markdown
Member

joostlek commented Jun 5, 2026

Let's throw the naming discussion in the core chat and see whats the best name to give it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants