Add support for HmIP-RGBW and HmIP-LSC in homematicip_cloud integration (#148639)

This commit is contained in:
hahn-th 2025-07-15 12:16:07 +02:00 committed by GitHub
parent 1cb278966c
commit ab187f39c2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 523 additions and 2 deletions

View File

@ -2,13 +2,20 @@
from __future__ import annotations from __future__ import annotations
import logging
from typing import Any from typing import Any
from homematicip.base.enums import DeviceType, OpticalSignalBehaviour, RGBColorState from homematicip.base.enums import (
DeviceType,
FunctionalChannelType,
OpticalSignalBehaviour,
RGBColorState,
)
from homematicip.base.functionalChannels import NotificationLightChannel from homematicip.base.functionalChannels import NotificationLightChannel
from homematicip.device import ( from homematicip.device import (
BrandDimmer, BrandDimmer,
BrandSwitchNotificationLight, BrandSwitchNotificationLight,
Device,
Dimmer, Dimmer,
DinRailDimmer3, DinRailDimmer3,
FullFlushDimmer, FullFlushDimmer,
@ -34,6 +41,8 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from .entity import HomematicipGenericEntity from .entity import HomematicipGenericEntity
from .hap import HomematicIPConfigEntry, HomematicipHAP from .hap import HomematicIPConfigEntry, HomematicipHAP
_logger = logging.getLogger(__name__)
async def async_setup_entry( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
@ -43,6 +52,14 @@ async def async_setup_entry(
"""Set up the HomematicIP Cloud lights from a config entry.""" """Set up the HomematicIP Cloud lights from a config entry."""
hap = config_entry.runtime_data hap = config_entry.runtime_data
entities: list[HomematicipGenericEntity] = [] entities: list[HomematicipGenericEntity] = []
entities.extend(
HomematicipLightHS(hap, d, ch.index)
for d in hap.home.devices
for ch in d.functionalChannels
if ch.functionalChannelType == FunctionalChannelType.UNIVERSAL_LIGHT_CHANNEL
)
for device in hap.home.devices: for device in hap.home.devices:
if ( if (
isinstance(device, SwitchMeasuring) isinstance(device, SwitchMeasuring)
@ -104,6 +121,64 @@ class HomematicipLight(HomematicipGenericEntity, LightEntity):
await self._device.turn_off_async() await self._device.turn_off_async()
class HomematicipLightHS(HomematicipGenericEntity, LightEntity):
"""Representation of the HomematicIP light with HS color mode."""
_attr_color_mode = ColorMode.HS
_attr_supported_color_modes = {ColorMode.HS}
def __init__(self, hap: HomematicipHAP, device: Device, channel_index: int) -> None:
"""Initialize the light entity."""
super().__init__(hap, device, channel=channel_index, is_multi_channel=True)
@property
def is_on(self) -> bool:
"""Return true if light is on."""
return self.functional_channel.on
@property
def brightness(self) -> int | None:
"""Return the current brightness."""
return int(self.functional_channel.dimLevel * 255.0)
@property
def hs_color(self) -> tuple[float, float] | None:
"""Return the hue and saturation color value [float, float]."""
if (
self.functional_channel.hue is None
or self.functional_channel.saturationLevel is None
):
return None
return (
self.functional_channel.hue,
self.functional_channel.saturationLevel * 100.0,
)
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the light on."""
hs_color = kwargs.get(ATTR_HS_COLOR, (0.0, 0.0))
hue = hs_color[0] % 360.0
saturation = hs_color[1] / 100.0
dim_level = round(kwargs.get(ATTR_BRIGHTNESS, 255) / 255.0, 2)
if ATTR_HS_COLOR not in kwargs:
hue = self.functional_channel.hue
saturation = self.functional_channel.saturationLevel
if ATTR_BRIGHTNESS not in kwargs:
# If no brightness is set, use the current brightness
dim_level = self.functional_channel.dimLevel or 1.0
await self.functional_channel.set_hue_saturation_dim_level_async(
hue=hue, saturation_level=saturation, dim_level=dim_level
)
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the light off."""
await self.functional_channel.set_switch_state_async(on=False)
class HomematicipLightMeasuring(HomematicipLight): class HomematicipLightMeasuring(HomematicipLight):
"""Representation of the HomematicIP measuring light.""" """Representation of the HomematicIP measuring light."""

View File

@ -8566,6 +8566,376 @@
"serializedGlobalTradeItemNumber": "3014F71100000000000SVCTH", "serializedGlobalTradeItemNumber": "3014F71100000000000SVCTH",
"type": "TEMPERATURE_HUMIDITY_SENSOR_COMPACT", "type": "TEMPERATURE_HUMIDITY_SENSOR_COMPACT",
"updateState": "UP_TO_DATE" "updateState": "UP_TO_DATE"
},
"3014F71100000000000RGBW2": {
"availableFirmwareVersion": "1.0.62",
"connectionType": "HMIP_RF",
"deviceArchetype": "HMIP",
"fastColorChangeSupported": true,
"firmwareVersion": "1.0.62",
"firmwareVersionInteger": 65598,
"functionalChannels": {
"0": {
"altitude": null,
"busConfigMismatch": null,
"coProFaulty": false,
"coProRestartNeeded": false,
"coProUpdateFailure": false,
"configPending": false,
"controlsMountingOrientation": null,
"daliBusState": null,
"dataDecodingFailedError": null,
"defaultLinkedGroup": [],
"deviceAliveSignalEnabled": null,
"deviceCommunicationError": null,
"deviceDriveError": null,
"deviceDriveModeError": null,
"deviceId": "3014F71100000000000RGBW2",
"deviceOperationMode": "UNIVERSAL_LIGHT_1_RGB",
"deviceOverheated": false,
"deviceOverloaded": false,
"devicePowerFailureDetected": false,
"deviceUndervoltage": false,
"displayContrast": null,
"displayMode": null,
"displayMountingOrientation": null,
"dutyCycle": false,
"frostProtectionError": null,
"frostProtectionErrorAcknowledged": null,
"functionalChannelType": "DEVICE_BASE",
"groupIndex": 0,
"groups": ["00000000-0000-0000-0000-000000000056"],
"index": 0,
"inputLayoutMode": null,
"invertedDisplayColors": null,
"label": "",
"lockJammed": null,
"lowBat": null,
"mountingModuleError": null,
"mountingOrientation": null,
"multicastRoutingEnabled": false,
"noDataFromLinkyError": null,
"operationDays": null,
"particulateMatterSensorCommunicationError": null,
"particulateMatterSensorError": null,
"powerShortCircuit": null,
"profilePeriodLimitReached": null,
"routerModuleEnabled": false,
"routerModuleSupported": false,
"rssiDeviceValue": -50,
"rssiPeerValue": null,
"sensorCommunicationError": null,
"sensorError": null,
"shortCircuitDataLine": null,
"supportedOptionalFeatures": {
"IFeatureBusConfigMismatch": false,
"IFeatureDataDecodingFailedError": false,
"IFeatureDeviceCoProError": false,
"IFeatureDeviceCoProRestart": false,
"IFeatureDeviceCoProUpdate": false,
"IFeatureDeviceCommunicationError": false,
"IFeatureDeviceDaliBusError": false,
"IFeatureDeviceDriveError": false,
"IFeatureDeviceDriveModeError": false,
"IFeatureDeviceIdentify": false,
"IFeatureDeviceMountingModuleError": false,
"IFeatureDeviceOverheated": true,
"IFeatureDeviceOverloaded": false,
"IFeatureDeviceParticulateMatterSensorCommunicationError": false,
"IFeatureDeviceParticulateMatterSensorError": false,
"IFeatureDevicePowerFailure": false,
"IFeatureDeviceSensorCommunicationError": false,
"IFeatureDeviceSensorError": false,
"IFeatureDeviceTempSensorError": false,
"IFeatureDeviceTemperatureHumiditySensorCommunicationError": false,
"IFeatureDeviceTemperatureHumiditySensorError": false,
"IFeatureDeviceTemperatureOutOfRange": false,
"IFeatureDeviceUndervoltage": false,
"IFeatureMulticastRouter": false,
"IFeatureNoDataFromLinkyError": false,
"IFeaturePowerShortCircuit": false,
"IFeatureProfilePeriodLimit": false,
"IFeatureRssiValue": true,
"IFeatureShortCircuitDataLine": false,
"IFeatureTicVersionError": false,
"IOptionalFeatureAltitude": false,
"IOptionalFeatureColorTemperature": false,
"IOptionalFeatureColorTemperatureDim2Warm": false,
"IOptionalFeatureColorTemperatureDynamicDaylight": false,
"IOptionalFeatureDefaultLinkedGroup": false,
"IOptionalFeatureDeviceAliveSignalEnabled": false,
"IOptionalFeatureDeviceErrorLockJammed": false,
"IOptionalFeatureDeviceFrostProtectionError": false,
"IOptionalFeatureDeviceInputLayoutMode": false,
"IOptionalFeatureDeviceOperationMode": true,
"IOptionalFeatureDeviceSwitchChannelMode": false,
"IOptionalFeatureDeviceValveError": false,
"IOptionalFeatureDeviceWaterError": false,
"IOptionalFeatureDimmerState": false,
"IOptionalFeatureDisplayContrast": false,
"IOptionalFeatureDisplayMode": false,
"IOptionalFeatureDutyCycle": true,
"IOptionalFeatureHardwareColorTemperature": false,
"IOptionalFeatureHueSaturationValue": false,
"IOptionalFeatureInvertedDisplayColors": false,
"IOptionalFeatureLightScene": false,
"IOptionalFeatureLightSceneWithShortTimes": false,
"IOptionalFeatureLowBat": false,
"IOptionalFeatureMountingOrientation": false,
"IOptionalFeatureOperationDays": false,
"IOptionalFeaturePowerUpColorTemperature": false,
"IOptionalFeaturePowerUpDimmerState": false,
"IOptionalFeaturePowerUpHueSaturationValue": false,
"IOptionalFeaturePowerUpSwitchState": false
},
"switchChannelMode": null,
"temperatureHumiditySensorCommunicationError": null,
"temperatureHumiditySensorError": null,
"temperatureOutOfRange": false,
"temperatureSensorError": null,
"ticVersionError": null,
"unreach": false,
"valveFlowError": null,
"valveWaterError": null
},
"1": {
"channelActive": true,
"channelRole": "UNIVERSAL_LIGHT_ACTUATOR",
"colorTemperature": null,
"connectedDeviceUnreach": null,
"controlGearFailure": null,
"deviceId": "3014F71100000000000RGBW2",
"dim2WarmActive": false,
"dimLevel": 0.68,
"functionalChannelType": "UNIVERSAL_LIGHT_CHANNEL",
"groupIndex": 1,
"groups": ["00000000-0000-0000-0000-000000000061"],
"hardwareColorTemperatureColdWhite": 6500,
"hardwareColorTemperatureWarmWhite": 2000,
"hue": 120,
"humanCentricLightActive": false,
"index": 1,
"label": "",
"lampFailure": null,
"lightSceneId": 1,
"limitFailure": null,
"maximumColorTemperature": 6500,
"minimalColorTemperature": 2000,
"on": true,
"onMinLevel": 0.05,
"powerUpColorTemperature": 10100,
"powerUpDimLevel": 1.0,
"powerUpHue": 361,
"powerUpSaturationLevel": 1.01,
"powerUpSwitchState": "PERMANENT_OFF",
"profileMode": "AUTOMATIC",
"rampTime": 0.5,
"saturationLevel": 0.8,
"supportedOptionalFeatures": {
"IFeatureConnectedDeviceUnreach": false,
"IFeatureControlGearFailure": false,
"IFeatureLampFailure": false,
"IFeatureLightGroupActuatorChannel": true,
"IFeatureLightProfileActuatorChannel": true,
"IFeatureLimitFailure": false,
"IOptionalFeatureChannelActive": false,
"IOptionalFeatureColorTemperature": false,
"IOptionalFeatureColorTemperatureDim2Warm": false,
"IOptionalFeatureColorTemperatureDynamicDaylight": false,
"IOptionalFeatureDimmerState": true,
"IOptionalFeatureHardwareColorTemperature": false,
"IOptionalFeatureHueSaturationValue": true,
"IOptionalFeatureLightScene": true,
"IOptionalFeatureLightSceneWithShortTimes": true,
"IOptionalFeatureOnMinLevel": true,
"IOptionalFeaturePowerUpColorTemperature": false,
"IOptionalFeaturePowerUpDimmerState": true,
"IOptionalFeaturePowerUpHueSaturationValue": true,
"IOptionalFeaturePowerUpSwitchState": true
},
"userDesiredProfileMode": "AUTOMATIC"
},
"2": {
"channelActive": false,
"channelRole": null,
"colorTemperature": null,
"connectedDeviceUnreach": null,
"controlGearFailure": null,
"deviceId": "3014F71100000000000RGBW2",
"dim2WarmActive": null,
"dimLevel": null,
"functionalChannelType": "UNIVERSAL_LIGHT_CHANNEL",
"groupIndex": 0,
"groups": [],
"hardwareColorTemperatureColdWhite": 6500,
"hardwareColorTemperatureWarmWhite": 2000,
"hue": null,
"humanCentricLightActive": null,
"index": 2,
"label": "",
"lampFailure": null,
"lightSceneId": null,
"limitFailure": null,
"maximumColorTemperature": 6500,
"minimalColorTemperature": 2000,
"on": null,
"onMinLevel": 0.05,
"powerUpColorTemperature": 10100,
"powerUpDimLevel": 1.0,
"powerUpHue": 361,
"powerUpSaturationLevel": 1.01,
"powerUpSwitchState": "PERMANENT_OFF",
"profileMode": "AUTOMATIC",
"rampTime": 0.5,
"saturationLevel": null,
"supportedOptionalFeatures": {
"IFeatureConnectedDeviceUnreach": false,
"IFeatureControlGearFailure": false,
"IFeatureLampFailure": false,
"IFeatureLimitFailure": false,
"IOptionalFeatureChannelActive": false,
"IOptionalFeatureColorTemperature": false,
"IOptionalFeatureColorTemperatureDim2Warm": false,
"IOptionalFeatureColorTemperatureDynamicDaylight": false,
"IOptionalFeatureDimmerState": false,
"IOptionalFeatureHardwareColorTemperature": false,
"IOptionalFeatureHueSaturationValue": false,
"IOptionalFeatureLightScene": false,
"IOptionalFeatureLightSceneWithShortTimes": false,
"IOptionalFeatureOnMinLevel": true,
"IOptionalFeaturePowerUpColorTemperature": false,
"IOptionalFeaturePowerUpDimmerState": false,
"IOptionalFeaturePowerUpHueSaturationValue": false,
"IOptionalFeaturePowerUpSwitchState": true
},
"userDesiredProfileMode": "AUTOMATIC"
},
"3": {
"channelActive": false,
"channelRole": null,
"colorTemperature": null,
"connectedDeviceUnreach": null,
"controlGearFailure": null,
"deviceId": "3014F71100000000000RGBW2",
"dim2WarmActive": null,
"dimLevel": null,
"functionalChannelType": "UNIVERSAL_LIGHT_CHANNEL",
"groupIndex": 0,
"groups": [],
"hardwareColorTemperatureColdWhite": 6500,
"hardwareColorTemperatureWarmWhite": 2000,
"hue": null,
"humanCentricLightActive": null,
"index": 3,
"label": "",
"lampFailure": null,
"lightSceneId": null,
"limitFailure": null,
"maximumColorTemperature": 6500,
"minimalColorTemperature": 2000,
"on": null,
"onMinLevel": 0.05,
"powerUpColorTemperature": 10100,
"powerUpDimLevel": 1.0,
"powerUpHue": 361,
"powerUpSaturationLevel": 1.01,
"powerUpSwitchState": "PERMANENT_OFF",
"profileMode": "AUTOMATIC",
"rampTime": 0.5,
"saturationLevel": null,
"supportedOptionalFeatures": {
"IFeatureConnectedDeviceUnreach": false,
"IFeatureControlGearFailure": false,
"IFeatureLampFailure": false,
"IFeatureLimitFailure": false,
"IOptionalFeatureChannelActive": false,
"IOptionalFeatureColorTemperature": false,
"IOptionalFeatureColorTemperatureDim2Warm": false,
"IOptionalFeatureColorTemperatureDynamicDaylight": false,
"IOptionalFeatureDimmerState": false,
"IOptionalFeatureHardwareColorTemperature": false,
"IOptionalFeatureHueSaturationValue": false,
"IOptionalFeatureLightScene": false,
"IOptionalFeatureLightSceneWithShortTimes": false,
"IOptionalFeatureOnMinLevel": true,
"IOptionalFeaturePowerUpColorTemperature": false,
"IOptionalFeaturePowerUpDimmerState": false,
"IOptionalFeaturePowerUpHueSaturationValue": false,
"IOptionalFeaturePowerUpSwitchState": true
},
"userDesiredProfileMode": "AUTOMATIC"
},
"4": {
"channelActive": false,
"channelRole": null,
"colorTemperature": null,
"connectedDeviceUnreach": null,
"controlGearFailure": null,
"deviceId": "3014F71100000000000RGBW2",
"dim2WarmActive": null,
"dimLevel": null,
"functionalChannelType": "UNIVERSAL_LIGHT_CHANNEL",
"groupIndex": 0,
"groups": [],
"hardwareColorTemperatureColdWhite": 6500,
"hardwareColorTemperatureWarmWhite": 2000,
"hue": null,
"humanCentricLightActive": null,
"index": 4,
"label": "",
"lampFailure": null,
"lightSceneId": null,
"limitFailure": null,
"maximumColorTemperature": 6500,
"minimalColorTemperature": 2000,
"on": null,
"onMinLevel": 0.05,
"powerUpColorTemperature": 10100,
"powerUpDimLevel": 1.0,
"powerUpHue": 361,
"powerUpSaturationLevel": 1.01,
"powerUpSwitchState": "PERMANENT_OFF",
"profileMode": "AUTOMATIC",
"rampTime": 0.5,
"saturationLevel": null,
"supportedOptionalFeatures": {
"IFeatureConnectedDeviceUnreach": false,
"IFeatureControlGearFailure": false,
"IFeatureLampFailure": false,
"IFeatureLimitFailure": false,
"IOptionalFeatureChannelActive": false,
"IOptionalFeatureColorTemperature": false,
"IOptionalFeatureColorTemperatureDim2Warm": false,
"IOptionalFeatureColorTemperatureDynamicDaylight": false,
"IOptionalFeatureDimmerState": false,
"IOptionalFeatureHardwareColorTemperature": false,
"IOptionalFeatureHueSaturationValue": false,
"IOptionalFeatureLightScene": false,
"IOptionalFeatureLightSceneWithShortTimes": false,
"IOptionalFeatureOnMinLevel": true,
"IOptionalFeaturePowerUpColorTemperature": false,
"IOptionalFeaturePowerUpDimmerState": false,
"IOptionalFeaturePowerUpHueSaturationValue": false,
"IOptionalFeaturePowerUpSwitchState": true
},
"userDesiredProfileMode": "AUTOMATIC"
}
},
"homeId": "00000000-0000-0000-0000-000000000001",
"id": "3014F71100000000000RGBW2",
"label": "RGBW Controller",
"lastStatusUpdate": 1749973334235,
"liveUpdateState": "LIVE_UPDATE_NOT_SUPPORTED",
"manuallyUpdateForced": false,
"manufacturerCode": 1,
"measuredAttributes": {},
"modelId": 462,
"modelType": "HmIP-RGBW",
"oem": "eQ-3",
"permanentlyReachable": true,
"serializedGlobalTradeItemNumber": "3014F71100000000000RGBW2",
"type": "RGBW_DIMMER",
"updateState": "UP_TO_DATE"
} }
}, },
"groups": { "groups": {

View File

@ -22,7 +22,7 @@ async def test_hmip_load_all_supported_devices(
test_devices=None, test_groups=None test_devices=None, test_groups=None
) )
assert len(mock_hap.hmip_device_by_entity_id) == 331 assert len(mock_hap.hmip_device_by_entity_id) == 335
async def test_hmip_remove_device( async def test_hmip_remove_device(

View File

@ -600,3 +600,79 @@ async def test_hmip_din_rail_dimmer_3_channel3(
ha_state = hass.states.get(entity_id) ha_state = hass.states.get(entity_id)
assert ha_state.state == STATE_OFF assert ha_state.state == STATE_OFF
assert not ha_state.attributes.get(ATTR_BRIGHTNESS) assert not ha_state.attributes.get(ATTR_BRIGHTNESS)
async def test_hmip_light_hs(
hass: HomeAssistant, default_mock_hap_factory: HomeFactory
) -> None:
"""Test HomematicipLight with HS color mode."""
entity_id = "light.rgbw_controller_channel1"
entity_name = "RGBW Controller Channel1"
device_model = "HmIP-RGBW"
mock_hap = await default_mock_hap_factory.async_get_mock_hap(
test_devices=["RGBW Controller"]
)
ha_state, hmip_device = get_and_check_entity_basics(
hass, mock_hap, entity_id, entity_name, device_model
)
assert ha_state.state == STATE_ON
assert ha_state.attributes[ATTR_COLOR_MODE] == ColorMode.HS
assert ha_state.attributes[ATTR_SUPPORTED_COLOR_MODES] == [ColorMode.HS]
service_call_counter = len(hmip_device.functionalChannels[1].mock_calls)
# Test turning on with HS color
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": entity_id, ATTR_HS_COLOR: [240.0, 100.0]},
blocking=True,
)
assert len(hmip_device.functionalChannels[1].mock_calls) == service_call_counter + 1
assert (
hmip_device.functionalChannels[1].mock_calls[-1][0]
== "set_hue_saturation_dim_level_async"
)
assert hmip_device.functionalChannels[1].mock_calls[-1][2] == {
"hue": 240.0,
"saturation_level": 1.0,
"dim_level": 0.68,
}
# Test turning on with HS color
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": entity_id, ATTR_HS_COLOR: [220.0, 80.0], ATTR_BRIGHTNESS: 123},
blocking=True,
)
assert len(hmip_device.functionalChannels[1].mock_calls) == service_call_counter + 2
assert (
hmip_device.functionalChannels[1].mock_calls[-1][0]
== "set_hue_saturation_dim_level_async"
)
assert hmip_device.functionalChannels[1].mock_calls[-1][2] == {
"hue": 220.0,
"saturation_level": 0.8,
"dim_level": 0.48,
}
# Test turning on with HS color
await hass.services.async_call(
"light",
"turn_on",
{"entity_id": entity_id, ATTR_BRIGHTNESS: 40},
blocking=True,
)
assert len(hmip_device.functionalChannels[1].mock_calls) == service_call_counter + 3
assert (
hmip_device.functionalChannels[1].mock_calls[-1][0]
== "set_hue_saturation_dim_level_async"
)
assert hmip_device.functionalChannels[1].mock_calls[-1][2] == {
"hue": hmip_device.functionalChannels[1].hue,
"saturation_level": hmip_device.functionalChannels[1].saturationLevel,
"dim_level": 0.16,
}