Skip to content

Add support for SwitchBot Ceiling Lights#159072

Merged
joostlek merged 4 commits into
home-assistant:devfrom
jklausa:feature/switchbot-ceiling-light
Dec 23, 2025
Merged

Add support for SwitchBot Ceiling Lights#159072
joostlek merged 4 commits into
home-assistant:devfrom
jklausa:feature/switchbot-ceiling-light

Conversation

@jklausa
Copy link
Copy Markdown
Contributor

@jklausa jklausa commented Dec 15, 2025

Proposed change

Adds support for Ceiling Light devices for SwitchBot Cloud integration.

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

  • This PR fixes or closes issue: fixes #
  • This PR is related to issue:
  • Link to documentation pull request:
  • Link to developer documentation pull request:
  • Link to frontend pull request:

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 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:

Copilot AI review requested due to automatic review settings December 15, 2025 09:01
@home-assistant
Copy link
Copy Markdown
Contributor

Hey there @SeraphicRav, @laurence-presland, @Gigatrappeur, @XiaoLing-git, mind taking a look at this pull request as it has been labeled with an integration (switchbot_cloud) you are listed as a code owner for? Thanks!

Code owner commands

Code owners of switchbot_cloud can trigger bot actions by commenting:

  • @home-assistant close Closes the pull request.
  • @home-assistant rename Awesome new title Renames the pull request.
  • @home-assistant reopen Reopen the pull request.
  • @home-assistant unassign switchbot_cloud Removes the current integration label and assignees on the pull request, add the integration domain after the command.
  • @home-assistant add-label needs-more-information Add a label (needs-more-information, problem in dependency, problem in custom component) to the pull request.
  • @home-assistant remove-label needs-more-information Remove a label (needs-more-information, problem in dependency, problem in custom component) on the pull request.

@jklausa
Copy link
Copy Markdown
Contributor Author

jklausa commented Dec 15, 2025

I have started working on this ages ago, but then kinda... forgot about it because things were working in my local fork; and in the meantime the code has shifted meaningfully, and the changes required now are very small :)

async def _send_color_temperature_command(self, color_temp_kelvin: int) -> None:
"""Send a color temperature command."""
await self.send_api_command(
CeilingLightCommands.SET_COLOR_TEMPERATURE,
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.

These, arguably, could be the same commands as RGBWWLightCommands, since they use the same actual commands (here: https://github.com/SeraphicCorp/py-switchbot-api/blob/main/switchbot_api/commands.py#L294C30-L294C49).

But they're separate on the py-switchbot-api side, so I've left them distinct here too. Maybe we should unify that somehow?

@jklausa
Copy link
Copy Markdown
Contributor Author

jklausa commented Dec 15, 2025

I'll take a look at adding some tests later today.

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

This PR adds support for SwitchBot Ceiling Light and Ceiling Light Pro devices to the SwitchBot Cloud integration. The implementation introduces a new entity class that supports color temperature control with brightness adjustment.

Key changes:

  • Adds SwitchBotCloudCeilingLight entity class with color temperature support (2700-6500K range)
  • Registers "Ceiling Light" and "Ceiling Light Pro" device types in the device discovery logic
  • Implements device-specific commands using CeilingLightCommands from the switchbot_api library

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
homeassistant/components/switchbot_cloud/light.py Adds SwitchBotCloudCeilingLight class with color temperature and brightness control, updates factory function to handle ceiling light device types
homeassistant/components/switchbot_cloud/init.py Registers "Ceiling Light" and "Ceiling Light Pro" device types for light platform discovery

Comment on lines +153 to +174
class SwitchBotCloudCeilingLight(SwitchBotCloudLight):
"""Representation of SwitchBot Ceiling Light."""

_attr_max_color_temp_kelvin = 6500
_attr_min_color_temp_kelvin = 2700

_attr_supported_color_modes = {ColorMode.COLOR_TEMP}

async def _send_brightness_command(self, brightness: int) -> None:
"""Send a brightness command."""
await self.send_api_command(
CeilingLightCommands.SET_BRIGHTNESS,
parameters=str(value_map_brightness(brightness)),
)

async def _send_color_temperature_command(self, color_temp_kelvin: int) -> None:
"""Send a color temperature command."""
await self.send_api_command(
CeilingLightCommands.SET_COLOR_TEMPERATURE,
parameters=str(color_temp_kelvin),
)

Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

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

The new SwitchBotCloudCeilingLight class lacks test coverage. Tests should be added to verify:

  1. Turn on/off functionality
  2. Brightness control using CeilingLightCommands.SET_BRIGHTNESS
  3. Color temperature control using CeilingLightCommands.SET_COLOR_TEMPERATURE
  4. Supported color modes (only COLOR_TEMP)
  5. Temperature range enforcement (2700-6500K)

Other light types in this integration have comprehensive tests (see test_strip_light_turn_on, test_rgbww_light_turn_on). Similar tests should be added for ceiling lights.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

that can happen in this PR

Comment on lines +174 to +175


Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

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

The base class async_turn_on method sets _attr_color_mode = ColorMode.RGB when adjusting brightness (line 88) or when turning on without parameters (line 97). However, SwitchBotCloudCeilingLight only supports ColorMode.COLOR_TEMP. This mismatch could cause the entity to report an incorrect color mode.

Consider overriding async_turn_on in SwitchBotCloudCeilingLight to set the correct color mode, or adjust the base class logic to check the supported color modes before setting the color mode.

Suggested change
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn on the ceiling light with the correct color mode."""
# Only COLOR_TEMP is supported
if (brightness := kwargs.get("brightness")) is not None:
await self._send_brightness_command(brightness)
if (color_temp := kwargs.get("color_temp_kelvin")) is not None:
await self._send_color_temperature_command(color_temp)
if not kwargs:
await self.send_api_command(CommonCommands.TURN_ON)
self._attr_is_on = True
self._attr_color_mode = ColorMode.COLOR_TEMP
await asyncio.sleep(AFTER_COMMAND_REFRESH)
await self.coordinator.async_request_refresh()

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member

@joostlek joostlek left a comment

Choose a reason for hiding this comment

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

Would it be possible to add tests to avoid regressions in the future?

@jklausa
Copy link
Copy Markdown
Contributor Author

jklausa commented Dec 19, 2025

Yes, sorry! Will do over the weekend, $Job got in the way in between.

@joostlek joostlek marked this pull request as draft December 19, 2025 13:28
@jklausa jklausa marked this pull request as ready for review December 22, 2025 17:44
@jklausa
Copy link
Copy Markdown
Contributor Author

jklausa commented Dec 22, 2025

Added some tests (full-disclosure: written with help of AI; though I did manually review them and made sure they made sense); and fixed the bug that Copilot noticed above; I did notice HASS complaining about this in my local instance in practice:
Screenshot 2025-12-23 at 02 46 27

@jklausa
Copy link
Copy Markdown
Contributor Author

jklausa commented Dec 22, 2025

If/when this is approved, Draft PR for docs update: home-assistant/home-assistant.io#42694

await self._send_color_temperature_command(color_temp_kelvin)
else:
self._attr_color_mode = ColorMode.RGB
self._attr_color_mode = self._get_default_color_mode()
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 whole _get_default_color_mode() is here to preserve the existing logic of updating the ColorMode here; but I am not sure why it's here in the first place.

Would just not updating the _attr_color_mode here (and in the brightness is not None case?) at all would be a better move? I don't fullly understand HASS internals to understand what the implications of that are, but it feels weird to always update this, even when only touching the brightness?

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 3 out of 3 changed files in this pull request and generated no new comments.

@jklausa jklausa requested a review from joostlek December 23, 2025 12:36
@joostlek joostlek merged commit 6bd8d12 into home-assistant:dev Dec 23, 2025
41 of 42 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Dec 24, 2025
@jklausa jklausa deleted the feature/switchbot-ceiling-light branch December 30, 2025 07:20
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants