diff --git a/tests/data/devices/awox-esmlfzm-w6-dimm.json b/tests/data/devices/awox-esmlfzm-w6-dimm.json index af7555a6d..8538477b2 100644 --- a/tests/data/devices/awox-esmlfzm-w6-dimm.json +++ b/tests/data/devices/awox-esmlfzm-w6-dimm.json @@ -519,21 +519,17 @@ "available": true, "on": true, "brightness": 254, - "xy_color": [ - 0, - 0 - ], + "xy_color": null, "color_temp": null, "effect_list": [ "off" ], "effect": "off", "supported_features": 40, - "color_mode": "xy", + "color_mode": "brightness", "supported_color_modes": [ "brightness", - "onoff", - "xy" + "onoff" ], "off_with_transition": false, "off_brightness": null diff --git a/tests/data/devices/gledopto-gl-c-009p.json b/tests/data/devices/gledopto-gl-c-009p.json index dc1dc4091..a46930a43 100644 --- a/tests/data/devices/gledopto-gl-c-009p.json +++ b/tests/data/devices/gledopto-gl-c-009p.json @@ -389,7 +389,7 @@ "off" ], "supported_features": 40, - "min_mireds": 158, + "min_mireds": 153, "max_mireds": 500 }, "state": { @@ -398,16 +398,15 @@ "on": false, "brightness": 166, "xy_color": null, - "color_temp": 500, + "color_temp": null, "effect_list": [ "off" ], "effect": "off", "supported_features": 40, - "color_mode": "color_temp", + "color_mode": "brightness", "supported_color_modes": [ "brightness", - "color_temp", "onoff" ], "off_with_transition": false, diff --git a/tests/data/devices/gledopto-gl-sd-301p.json b/tests/data/devices/gledopto-gl-sd-301p.json new file mode 100644 index 000000000..55ce71078 --- /dev/null +++ b/tests/data/devices/gledopto-gl-sd-301p.json @@ -0,0 +1,729 @@ +{ + "version": 1, + "ieee": "ab:cd:ef:12:40:cb:4a:aa", + "nwk": "0x0579", + "manufacturer": "GLEDOPTO", + "model": "GL-SD-301P", + "friendly_manufacturer": "GLEDOPTO", + "friendly_model": "GL-SD-301P", + "name": "GLEDOPTO GL-SD-301P", + "quirk_applied": false, + "quirk_class": "zigpy.device.Device", + "exposes_features": [], + "manufacturer_code": 4687, + "power_source": "Mains", + "lqi": 120, + "rssi": -81, + "last_seen": "2026-03-09T17:34:19.703206+00:00", + "available": true, + "device_type": "Router", + "active_coordinator": false, + "node_descriptor": { + "logical_type": "Router", + "complex_descriptor_available": false, + "user_descriptor_available": false, + "reserved": 0, + "aps_flags": 0, + "frequency_band": 8, + "mac_capability_flags": 142, + "manufacturer_code": 4687, + "maximum_buffer_size": 66, + "maximum_incoming_transfer_size": 66, + "server_mask": 10752, + "maximum_outgoing_transfer_size": 66, + "descriptor_capability_field": 0 + }, + "endpoints": { + "11": { + "profile_id": 260, + "device_type": { + "name": "DIMMABLE_LIGHT", + "id": 257 + }, + "in_clusters": [ + { + "cluster_id": "0x0000", + "endpoint_attribute": "basic", + "attributes": [ + { + "id": "0x0004", + "name": "manufacturer", + "zcl_type": "string", + "value": "GLEDOPTO" + }, + { + "id": "0x0005", + "name": "model", + "zcl_type": "string", + "value": "GL-SD-301P" + } + ] + }, + { + "cluster_id": "0x0003", + "endpoint_attribute": "identify", + "attributes": [] + }, + { + "cluster_id": "0x0004", + "endpoint_attribute": "groups", + "attributes": [] + }, + { + "cluster_id": "0x0005", + "endpoint_attribute": "scenes", + "attributes": [] + }, + { + "cluster_id": "0x0006", + "endpoint_attribute": "on_off", + "attributes": [ + { + "id": "0x0000", + "name": "on_off", + "zcl_type": "bool", + "value": 1 + }, + { + "id": "0x4003", + "name": "start_up_on_off", + "zcl_type": "enum8", + "value": 1 + } + ] + }, + { + "cluster_id": "0x0008", + "endpoint_attribute": "level", + "attributes": [ + { + "id": "0x0000", + "name": "current_level", + "zcl_type": "uint8", + "value": 254 + }, + { + "id": "0x0014", + "name": "default_move_rate", + "zcl_type": "uint8", + "unsupported": true + }, + { + "id": "0x0013", + "name": "off_transition_time", + "zcl_type": "uint16", + "unsupported": true + }, + { + "id": "0x0011", + "name": "on_level", + "zcl_type": "uint8", + "unsupported": true + }, + { + "id": "0x0010", + "name": "on_off_transition_time", + "zcl_type": "uint16", + "unsupported": true + }, + { + "id": "0x0012", + "name": "on_transition_time", + "zcl_type": "uint16", + "unsupported": true + }, + { + "id": "0x4000", + "name": "start_up_current_level", + "zcl_type": "uint8", + "value": 255 + } + ] + }, + { + "cluster_id": "0x0300", + "endpoint_attribute": "light_color", + "attributes": [ + { + "id": "0x400a", + "name": "color_capabilities", + "zcl_type": "map16", + "value": 0 + }, + { + "id": "0x4002", + "name": "color_loop_active", + "zcl_type": "uint8", + "value": 0 + }, + { + "id": "0x0008", + "name": "color_mode", + "zcl_type": "enum8", + "value": 5 + }, + { + "id": "0x400c", + "name": "color_temp_physical_max", + "zcl_type": "uint16", + "value": 495 + }, + { + "id": "0x400b", + "name": "color_temp_physical_min", + "zcl_type": "uint16", + "value": 158 + }, + { + "id": "0x0007", + "name": "color_temperature", + "zcl_type": "uint16", + "value": 495 + }, + { + "id": "0x0003", + "name": "current_x", + "zcl_type": "uint16", + "value": 11653 + }, + { + "id": "0x0004", + "name": "current_y", + "zcl_type": "uint16", + "value": 46664 + }, + { + "id": "0x000f", + "name": "options", + "zcl_type": "map8", + "value": 0 + }, + { + "id": "0x4010", + "name": "start_up_color_temperature", + "zcl_type": "uint16", + "value": 65535 + } + ] + }, + { + "cluster_id": "0x1000", + "endpoint_attribute": "lightlink", + "attributes": [] + } + ], + "out_clusters": [ + { + "cluster_id": "0x0019", + "endpoint_attribute": "ota", + "attributes": [ + { + "id": "0x0002", + "name": "current_file_version", + "zcl_type": "uint32", + "value": 637612033 + } + ] + } + ] + }, + "242": { + "profile_id": 41440, + "device_type": { + "name": "PROXY_BASIC", + "id": 97 + }, + "in_clusters": [], + "out_clusters": [ + { + "cluster_id": "0x0021", + "endpoint_attribute": "green_power", + "attributes": [] + } + ] + } + }, + "original_signature": { + "manufacturer": "GLEDOPTO", + "model": "GL-SD-301P", + "node_desc": { + "logical_type": 1, + "complex_descriptor_available": 0, + "user_descriptor_available": 0, + "reserved": 0, + "aps_flags": 0, + "frequency_band": 8, + "mac_capability_flags": 142, + "manufacturer_code": 4687, + "maximum_buffer_size": 66, + "maximum_incoming_transfer_size": 66, + "server_mask": 10752, + "maximum_outgoing_transfer_size": 66, + "descriptor_capability_field": 0 + }, + "endpoints": { + "11": { + "profile_id": "0x0104", + "device_type": "0x0101", + "input_clusters": [ + "0x0000", + "0x0003", + "0x0004", + "0x0005", + "0x0006", + "0x0008", + "0x0300", + "0x1000" + ], + "output_clusters": [ + "0x0019" + ] + }, + "242": { + "profile_id": "0xa1e0", + "device_type": "0x0061", + "input_clusters": [], + "output_clusters": [ + "0x0021" + ] + } + } + }, + "zha_lib_entities": { + "button": [ + { + "info_object": { + "fallback_name": null, + "unique_id": "ab:cd:ef:12:40:cb:4a:aa-11-3", + "migrate_unique_ids": [], + "platform": "button", + "class_name": "IdentifyButton", + "translation_key": null, + "translation_placeholders": null, + "device_class": "identify", + "state_class": null, + "entity_category": "diagnostic", + "entity_registry_enabled_default": true, + "enabled": true, + "primary": false, + "cluster_handlers": [ + { + "class_name": "IdentifyClusterHandler", + "generic_id": "cluster_handler_0x0003", + "endpoint_id": 11, + "cluster": { + "id": 3, + "name": "Identify", + "type": "server" + }, + "id": "11:0x0003", + "unique_id": "ab:cd:ef:12:40:cb:4a:aa:11:0x0003", + "status": "INITIALIZED", + "value_attribute": null + } + ], + "device_ieee": "ab:cd:ef:12:40:cb:4a:aa", + "endpoint_id": 11, + "available": true, + "group_id": null, + "command": "identify", + "args": [ + 5 + ], + "kwargs": {} + }, + "state": { + "class_name": "IdentifyButton", + "available": true + } + } + ], + "light": [ + { + "info_object": { + "fallback_name": null, + "unique_id": "ab:cd:ef:12:40:cb:4a:aa-11", + "migrate_unique_ids": [], + "platform": "light", + "class_name": "Light", + "translation_key": "light", + "translation_placeholders": null, + "device_class": null, + "state_class": null, + "entity_category": null, + "entity_registry_enabled_default": true, + "enabled": true, + "primary": true, + "cluster_handlers": [ + { + "class_name": "OnOffClusterHandler", + "generic_id": "cluster_handler_0x0006", + "endpoint_id": 11, + "cluster": { + "id": 6, + "name": "On/Off", + "type": "server" + }, + "id": "11:0x0006", + "unique_id": "ab:cd:ef:12:40:cb:4a:aa:11:0x0006", + "status": "INITIALIZED", + "value_attribute": "on_off" + }, + { + "class_name": "LevelControlClusterHandler", + "generic_id": "cluster_handler_0x0008", + "endpoint_id": 11, + "cluster": { + "id": 8, + "name": "Level control", + "type": "server" + }, + "id": "11:0x0008", + "unique_id": "ab:cd:ef:12:40:cb:4a:aa:11:0x0008", + "status": "INITIALIZED", + "value_attribute": "current_level" + }, + { + "class_name": "ColorClusterHandler", + "generic_id": "cluster_handler_0x0300", + "endpoint_id": 11, + "cluster": { + "id": 768, + "name": "Color Control", + "type": "server" + }, + "id": "11:0x0300", + "unique_id": "ab:cd:ef:12:40:cb:4a:aa:11:0x0300", + "status": "INITIALIZED", + "value_attribute": "current_x" + } + ], + "device_ieee": "ab:cd:ef:12:40:cb:4a:aa", + "endpoint_id": 11, + "available": true, + "group_id": null, + "effect_list": [ + "off" + ], + "supported_features": 40, + "min_mireds": 153, + "max_mireds": 500 + }, + "state": { + "class_name": "Light", + "available": true, + "on": true, + "brightness": 254, + "xy_color": null, + "color_temp": null, + "effect_list": [ + "off" + ], + "effect": "off", + "supported_features": 40, + "color_mode": "brightness", + "supported_color_modes": [ + "brightness", + "onoff" + ], + "off_with_transition": false, + "off_brightness": null + }, + "extra_state_attributes": [ + "off_brightness", + "off_with_transition" + ] + } + ], + "number": [ + { + "info_object": { + "fallback_name": null, + "unique_id": "ab:cd:ef:12:40:cb:4a:aa-11-768-start_up_color_temperature", + "migrate_unique_ids": [], + "platform": "number", + "class_name": "StartUpColorTemperatureConfigurationEntity", + "translation_key": "start_up_color_temperature", + "translation_placeholders": null, + "device_class": null, + "state_class": null, + "entity_category": "config", + "entity_registry_enabled_default": true, + "enabled": true, + "primary": false, + "cluster_handlers": [ + { + "class_name": "ColorClusterHandler", + "generic_id": "cluster_handler_0x0300", + "endpoint_id": 11, + "cluster": { + "id": 768, + "name": "Color Control", + "type": "server" + }, + "id": "11:0x0300", + "unique_id": "ab:cd:ef:12:40:cb:4a:aa:11:0x0300", + "status": "INITIALIZED", + "value_attribute": "current_x" + } + ], + "device_ieee": "ab:cd:ef:12:40:cb:4a:aa", + "endpoint_id": 11, + "available": true, + "group_id": null, + "mode": "auto", + "native_max_value": 495, + "native_min_value": 158, + "native_step": 1.0, + "native_unit_of_measurement": null + }, + "state": { + "class_name": "StartUpColorTemperatureConfigurationEntity", + "available": true, + "state": 65535 + } + }, + { + "info_object": { + "fallback_name": null, + "unique_id": "ab:cd:ef:12:40:cb:4a:aa-11-8-start_up_current_level", + "migrate_unique_ids": [], + "platform": "number", + "class_name": "StartUpCurrentLevelConfigurationEntity", + "translation_key": "start_up_current_level", + "translation_placeholders": null, + "device_class": null, + "state_class": null, + "entity_category": "config", + "entity_registry_enabled_default": true, + "enabled": true, + "primary": false, + "cluster_handlers": [ + { + "class_name": "LevelControlClusterHandler", + "generic_id": "cluster_handler_0x0008", + "endpoint_id": 11, + "cluster": { + "id": 8, + "name": "Level control", + "type": "server" + }, + "id": "11:0x0008", + "unique_id": "ab:cd:ef:12:40:cb:4a:aa:11:0x0008", + "status": "INITIALIZED", + "value_attribute": "current_level" + } + ], + "device_ieee": "ab:cd:ef:12:40:cb:4a:aa", + "endpoint_id": 11, + "available": true, + "group_id": null, + "mode": "auto", + "native_max_value": 255, + "native_min_value": 0, + "native_step": 1.0, + "native_unit_of_measurement": null + }, + "state": { + "class_name": "StartUpCurrentLevelConfigurationEntity", + "available": true, + "state": 255 + } + } + ], + "select": [ + { + "info_object": { + "fallback_name": null, + "unique_id": "ab:cd:ef:12:40:cb:4a:aa-11-6-StartUpOnOff", + "migrate_unique_ids": [], + "platform": "select", + "class_name": "StartupOnOffSelectEntity", + "translation_key": "start_up_on_off", + "translation_placeholders": null, + "device_class": null, + "state_class": null, + "entity_category": "config", + "entity_registry_enabled_default": true, + "enabled": true, + "primary": false, + "cluster_handlers": [ + { + "class_name": "OnOffClusterHandler", + "generic_id": "cluster_handler_0x0006", + "endpoint_id": 11, + "cluster": { + "id": 6, + "name": "On/Off", + "type": "server" + }, + "id": "11:0x0006", + "unique_id": "ab:cd:ef:12:40:cb:4a:aa:11:0x0006", + "status": "INITIALIZED", + "value_attribute": "on_off" + } + ], + "device_ieee": "ab:cd:ef:12:40:cb:4a:aa", + "endpoint_id": 11, + "available": true, + "group_id": null, + "enum": "StartUpOnOff", + "options": [ + "Off", + "On", + "Toggle", + "PreviousValue" + ] + }, + "state": { + "class_name": "StartupOnOffSelectEntity", + "available": true, + "state": "On" + } + } + ], + "sensor": [ + { + "info_object": { + "fallback_name": null, + "unique_id": "ab:cd:ef:12:40:cb:4a:aa-11-0-lqi", + "migrate_unique_ids": [], + "platform": "sensor", + "class_name": "LQISensor", + "translation_key": "lqi", + "translation_placeholders": null, + "device_class": null, + "state_class": "measurement", + "entity_category": "diagnostic", + "entity_registry_enabled_default": false, + "enabled": true, + "primary": false, + "cluster_handlers": [ + { + "class_name": "BasicClusterHandler", + "generic_id": "cluster_handler_0x0000", + "endpoint_id": 11, + "cluster": { + "id": 0, + "name": "Basic", + "type": "server" + }, + "id": "11:0x0000", + "unique_id": "ab:cd:ef:12:40:cb:4a:aa:11:0x0000", + "status": "INITIALIZED", + "value_attribute": null + } + ], + "device_ieee": "ab:cd:ef:12:40:cb:4a:aa", + "endpoint_id": 11, + "available": true, + "group_id": null, + "suggested_display_precision": null, + "unit": null + }, + "state": { + "class_name": "LQISensor", + "available": true, + "state": 120 + } + }, + { + "info_object": { + "fallback_name": null, + "unique_id": "ab:cd:ef:12:40:cb:4a:aa-11-0-rssi", + "migrate_unique_ids": [], + "platform": "sensor", + "class_name": "RSSISensor", + "translation_key": "rssi", + "translation_placeholders": null, + "device_class": "signal_strength", + "state_class": "measurement", + "entity_category": "diagnostic", + "entity_registry_enabled_default": false, + "enabled": true, + "primary": false, + "cluster_handlers": [ + { + "class_name": "BasicClusterHandler", + "generic_id": "cluster_handler_0x0000", + "endpoint_id": 11, + "cluster": { + "id": 0, + "name": "Basic", + "type": "server" + }, + "id": "11:0x0000", + "unique_id": "ab:cd:ef:12:40:cb:4a:aa:11:0x0000", + "status": "INITIALIZED", + "value_attribute": null + } + ], + "device_ieee": "ab:cd:ef:12:40:cb:4a:aa", + "endpoint_id": 11, + "available": true, + "group_id": null, + "suggested_display_precision": null, + "unit": "dBm" + }, + "state": { + "class_name": "RSSISensor", + "available": true, + "state": -81 + } + } + ], + "update": [ + { + "info_object": { + "fallback_name": null, + "unique_id": "ab:cd:ef:12:40:cb:4a:aa-11-25-firmware_update", + "migrate_unique_ids": [], + "platform": "update", + "class_name": "FirmwareUpdateEntity", + "translation_key": null, + "translation_placeholders": null, + "device_class": "firmware", + "state_class": null, + "entity_category": "config", + "entity_registry_enabled_default": true, + "enabled": true, + "primary": false, + "cluster_handlers": [ + { + "class_name": "OtaClientClusterHandler", + "generic_id": "cluster_handler_0x0019_client", + "endpoint_id": 11, + "cluster": { + "id": 25, + "name": "Ota", + "type": "client" + }, + "id": "11:0x0019_client", + "unique_id": "ab:cd:ef:12:40:cb:4a:aa:11:0x0019_CLIENT", + "status": "INITIALIZED", + "value_attribute": null + } + ], + "device_ieee": "ab:cd:ef:12:40:cb:4a:aa", + "endpoint_id": 11, + "available": true, + "group_id": null, + "supported_features": 7 + }, + "state": { + "class_name": "FirmwareUpdateEntity", + "available": true, + "installed_version": "0x26013001", + "in_progress": false, + "update_percentage": null, + "latest_version": null, + "release_summary": null, + "release_notes": null, + "release_url": null + } + } + ] + }, + "neighbors": [], + "routes": [] +} \ No newline at end of file diff --git a/tests/data/devices/sengled-z01-a19nae26.json b/tests/data/devices/sengled-z01-a19nae26.json index 39c38c4ed..36bccd800 100644 --- a/tests/data/devices/sengled-z01-a19nae26.json +++ b/tests/data/devices/sengled-z01-a19nae26.json @@ -505,7 +505,7 @@ ], "supported_features": 40, "min_mireds": 153, - "max_mireds": 370 + "max_mireds": 500 }, "state": { "class_name": "MinTransitionLight", @@ -513,16 +513,15 @@ "on": false, "brightness": 252, "xy_color": null, - "color_temp": 370, + "color_temp": null, "effect_list": [ "off" ], "effect": "off", "supported_features": 40, - "color_mode": "color_temp", + "color_mode": "brightness", "supported_color_modes": [ "brightness", - "color_temp", "onoff" ], "off_with_transition": false, diff --git a/tests/data/devices/tz3000-5fkufhn1-ts0502a.json b/tests/data/devices/tz3000-5fkufhn1-ts0502a.json index 48ef36c7c..65417a58b 100644 --- a/tests/data/devices/tz3000-5fkufhn1-ts0502a.json +++ b/tests/data/devices/tz3000-5fkufhn1-ts0502a.json @@ -431,10 +431,7 @@ "available": true, "on": false, "brightness": 254, - "xy_color": [ - 0.6999923704890516, - 0.29999237048905164 - ], + "xy_color": null, "color_temp": 193, "effect_list": [ "off" @@ -445,8 +442,7 @@ "supported_color_modes": [ "brightness", "color_temp", - "onoff", - "xy" + "onoff" ], "off_with_transition": false, "off_brightness": null diff --git a/tests/data/devices/tzb210-lmqquxus-ts0502b.json b/tests/data/devices/tzb210-lmqquxus-ts0502b.json new file mode 100644 index 000000000..261ab6cb7 --- /dev/null +++ b/tests/data/devices/tzb210-lmqquxus-ts0502b.json @@ -0,0 +1,662 @@ +{ + "version": 1, + "ieee": "ab:cd:ef:12:02:78:f7:ef", + "nwk": "0xBC00", + "manufacturer": "_TZB210_lmqquxus", + "model": "TS0502B", + "friendly_manufacturer": "_TZB210_lmqquxus", + "friendly_model": "TS0502B", + "name": "_TZB210_lmqquxus TS0502B", + "quirk_applied": false, + "quirk_class": "zigpy.device.Device", + "exposes_features": [], + "manufacturer_code": 4417, + "power_source": "Mains", + "lqi": 132, + "rssi": -67, + "last_seen": "2026-03-07T22:15:30.511073+00:00", + "available": true, + "device_type": "Router", + "active_coordinator": false, + "node_descriptor": { + "logical_type": "Router", + "complex_descriptor_available": false, + "user_descriptor_available": false, + "reserved": 0, + "aps_flags": 0, + "frequency_band": 8, + "mac_capability_flags": 142, + "manufacturer_code": 4417, + "maximum_buffer_size": 66, + "maximum_incoming_transfer_size": 66, + "server_mask": 10752, + "maximum_outgoing_transfer_size": 66, + "descriptor_capability_field": 0 + }, + "endpoints": { + "1": { + "profile_id": 260, + "device_type": { + "name": "COLOR_TEMPERATURE_LIGHT", + "id": 268 + }, + "in_clusters": [ + { + "cluster_id": "0x0000", + "endpoint_attribute": "basic", + "attributes": [ + { + "id": "0x0004", + "name": "manufacturer", + "zcl_type": "string", + "value": "_TZB210_lmqquxus" + }, + { + "id": "0x0005", + "name": "model", + "zcl_type": "string", + "value": "TS0502B" + } + ] + }, + { + "cluster_id": "0x0003", + "endpoint_attribute": "identify", + "attributes": [] + }, + { + "cluster_id": "0x0004", + "endpoint_attribute": "groups", + "attributes": [] + }, + { + "cluster_id": "0x0005", + "endpoint_attribute": "scenes", + "attributes": [] + }, + { + "cluster_id": "0x0006", + "endpoint_attribute": "on_off", + "attributes": [ + { + "id": "0x0000", + "name": "on_off", + "zcl_type": "bool", + "value": 1 + }, + { + "id": "0x4003", + "name": "start_up_on_off", + "zcl_type": "enum8", + "unsupported": true + } + ] + }, + { + "cluster_id": "0x0008", + "endpoint_attribute": "level", + "attributes": [ + { + "id": "0x0000", + "name": "current_level", + "zcl_type": "uint8", + "value": 232 + }, + { + "id": "0x0014", + "name": "default_move_rate", + "zcl_type": "uint8", + "unsupported": true + }, + { + "id": "0x0013", + "name": "off_transition_time", + "zcl_type": "uint16", + "unsupported": true + }, + { + "id": "0x0011", + "name": "on_level", + "zcl_type": "uint8", + "unsupported": true + }, + { + "id": "0x0010", + "name": "on_off_transition_time", + "zcl_type": "uint16", + "unsupported": true + }, + { + "id": "0x0012", + "name": "on_transition_time", + "zcl_type": "uint16", + "unsupported": true + }, + { + "id": "0x4000", + "name": "start_up_current_level", + "zcl_type": "uint8", + "unsupported": true + } + ] + }, + { + "cluster_id": "0x0300", + "endpoint_attribute": "light_color", + "attributes": [ + { + "id": "0x400a", + "name": "color_capabilities", + "zcl_type": "map16", + "value": 16 + }, + { + "id": "0x4002", + "name": "color_loop_active", + "zcl_type": "uint8", + "unsupported": true + }, + { + "id": "0x0008", + "name": "color_mode", + "zcl_type": "enum8", + "value": 0 + }, + { + "id": "0x400c", + "name": "color_temp_physical_max", + "zcl_type": "uint16", + "value": 500 + }, + { + "id": "0x400b", + "name": "color_temp_physical_min", + "zcl_type": "uint16", + "value": 153 + }, + { + "id": "0x0007", + "name": "color_temperature", + "zcl_type": "uint16", + "value": 0 + }, + { + "id": "0x0000", + "name": "current_hue", + "zcl_type": "uint8", + "value": 16 + }, + { + "id": "0x0001", + "name": "current_saturation", + "zcl_type": "uint8", + "unsupported": true + }, + { + "id": "0x0003", + "name": "current_x", + "zcl_type": "uint16", + "unsupported": true + }, + { + "id": "0x0004", + "name": "current_y", + "zcl_type": "uint16", + "unsupported": true + }, + { + "id": "0x4000", + "name": "enhanced_current_hue", + "zcl_type": "uint16", + "unsupported": true + }, + { + "id": "0x000f", + "name": "options", + "zcl_type": "map8", + "value": 0 + }, + { + "id": "0x4010", + "name": "start_up_color_temperature", + "zcl_type": "uint16", + "value": 153 + } + ] + }, + { + "cluster_id": "0x1000", + "endpoint_attribute": "lightlink", + "attributes": [] + }, + { + "cluster_id": "0xef00", + "endpoint_attribute": null, + "attributes": [] + } + ], + "out_clusters": [ + { + "cluster_id": "0x000a", + "endpoint_attribute": "time", + "attributes": [] + }, + { + "cluster_id": "0x0019", + "endpoint_attribute": "ota", + "attributes": [ + { + "id": "0x0002", + "name": "current_file_version", + "zcl_type": "uint32", + "value": 64 + } + ] + } + ] + }, + "242": { + "profile_id": 41440, + "device_type": { + "name": "PROXY_BASIC", + "id": 97 + }, + "in_clusters": [], + "out_clusters": [ + { + "cluster_id": "0x0021", + "endpoint_attribute": "green_power", + "attributes": [] + } + ] + } + }, + "original_signature": { + "manufacturer": "_TZB210_lmqquxus", + "model": "TS0502B", + "node_desc": { + "logical_type": 1, + "complex_descriptor_available": 0, + "user_descriptor_available": 0, + "reserved": 0, + "aps_flags": 0, + "frequency_band": 8, + "mac_capability_flags": 142, + "manufacturer_code": 4417, + "maximum_buffer_size": 66, + "maximum_incoming_transfer_size": 66, + "server_mask": 10752, + "maximum_outgoing_transfer_size": 66, + "descriptor_capability_field": 0 + }, + "endpoints": { + "1": { + "profile_id": "0x0104", + "device_type": "0x010c", + "input_clusters": [ + "0x0003", + "0x0004", + "0x0005", + "0x0006", + "0x1000", + "0x0008", + "0x0300", + "0xef00", + "0x0000" + ], + "output_clusters": [ + "0x0019", + "0x000a" + ] + }, + "242": { + "profile_id": "0xa1e0", + "device_type": "0x0061", + "input_clusters": [], + "output_clusters": [ + "0x0021" + ] + } + } + }, + "zha_lib_entities": { + "button": [ + { + "info_object": { + "fallback_name": null, + "unique_id": "ab:cd:ef:12:02:78:f7:ef-1-3", + "migrate_unique_ids": [], + "platform": "button", + "class_name": "IdentifyButton", + "translation_key": null, + "translation_placeholders": null, + "device_class": "identify", + "state_class": null, + "entity_category": "diagnostic", + "entity_registry_enabled_default": true, + "enabled": true, + "primary": false, + "cluster_handlers": [ + { + "class_name": "IdentifyClusterHandler", + "generic_id": "cluster_handler_0x0003", + "endpoint_id": 1, + "cluster": { + "id": 3, + "name": "Identify", + "type": "server" + }, + "id": "1:0x0003", + "unique_id": "ab:cd:ef:12:02:78:f7:ef:1:0x0003", + "status": "INITIALIZED", + "value_attribute": null + } + ], + "device_ieee": "ab:cd:ef:12:02:78:f7:ef", + "endpoint_id": 1, + "available": true, + "group_id": null, + "command": "identify", + "args": [ + 5 + ], + "kwargs": {} + }, + "state": { + "class_name": "IdentifyButton", + "available": true + } + } + ], + "light": [ + { + "info_object": { + "fallback_name": null, + "unique_id": "ab:cd:ef:12:02:78:f7:ef-1", + "migrate_unique_ids": [], + "platform": "light", + "class_name": "Light", + "translation_key": "light", + "translation_placeholders": null, + "device_class": null, + "state_class": null, + "entity_category": null, + "entity_registry_enabled_default": true, + "enabled": true, + "primary": true, + "cluster_handlers": [ + { + "class_name": "OnOffClusterHandler", + "generic_id": "cluster_handler_0x0006", + "endpoint_id": 1, + "cluster": { + "id": 6, + "name": "On/Off", + "type": "server" + }, + "id": "1:0x0006", + "unique_id": "ab:cd:ef:12:02:78:f7:ef:1:0x0006", + "status": "INITIALIZED", + "value_attribute": "on_off" + }, + { + "class_name": "LevelControlClusterHandler", + "generic_id": "cluster_handler_0x0008", + "endpoint_id": 1, + "cluster": { + "id": 8, + "name": "Level control", + "type": "server" + }, + "id": "1:0x0008", + "unique_id": "ab:cd:ef:12:02:78:f7:ef:1:0x0008", + "status": "INITIALIZED", + "value_attribute": "current_level" + }, + { + "class_name": "ColorClusterHandler", + "generic_id": "cluster_handler_0x0300", + "endpoint_id": 1, + "cluster": { + "id": 768, + "name": "Color Control", + "type": "server" + }, + "id": "1:0x0300", + "unique_id": "ab:cd:ef:12:02:78:f7:ef:1:0x0300", + "status": "INITIALIZED", + "value_attribute": "current_x" + } + ], + "device_ieee": "ab:cd:ef:12:02:78:f7:ef", + "endpoint_id": 1, + "available": true, + "group_id": null, + "effect_list": [ + "off" + ], + "supported_features": 40, + "min_mireds": 153, + "max_mireds": 500 + }, + "state": { + "class_name": "Light", + "available": true, + "on": true, + "brightness": 232, + "xy_color": null, + "color_temp": 0, + "effect_list": [ + "off" + ], + "effect": "off", + "supported_features": 40, + "color_mode": "color_temp", + "supported_color_modes": [ + "brightness", + "color_temp", + "onoff" + ], + "off_with_transition": false, + "off_brightness": null + }, + "extra_state_attributes": [ + "off_brightness", + "off_with_transition" + ] + } + ], + "number": [ + { + "info_object": { + "fallback_name": null, + "unique_id": "ab:cd:ef:12:02:78:f7:ef-1-768-start_up_color_temperature", + "migrate_unique_ids": [], + "platform": "number", + "class_name": "StartUpColorTemperatureConfigurationEntity", + "translation_key": "start_up_color_temperature", + "translation_placeholders": null, + "device_class": null, + "state_class": null, + "entity_category": "config", + "entity_registry_enabled_default": true, + "enabled": true, + "primary": false, + "cluster_handlers": [ + { + "class_name": "ColorClusterHandler", + "generic_id": "cluster_handler_0x0300", + "endpoint_id": 1, + "cluster": { + "id": 768, + "name": "Color Control", + "type": "server" + }, + "id": "1:0x0300", + "unique_id": "ab:cd:ef:12:02:78:f7:ef:1:0x0300", + "status": "INITIALIZED", + "value_attribute": "current_x" + } + ], + "device_ieee": "ab:cd:ef:12:02:78:f7:ef", + "endpoint_id": 1, + "available": true, + "group_id": null, + "mode": "auto", + "native_max_value": 500, + "native_min_value": 153, + "native_step": 1.0, + "native_unit_of_measurement": null + }, + "state": { + "class_name": "StartUpColorTemperatureConfigurationEntity", + "available": true, + "state": 153 + } + } + ], + "sensor": [ + { + "info_object": { + "fallback_name": null, + "unique_id": "ab:cd:ef:12:02:78:f7:ef-1-0-lqi", + "migrate_unique_ids": [], + "platform": "sensor", + "class_name": "LQISensor", + "translation_key": "lqi", + "translation_placeholders": null, + "device_class": null, + "state_class": "measurement", + "entity_category": "diagnostic", + "entity_registry_enabled_default": false, + "enabled": true, + "primary": false, + "cluster_handlers": [ + { + "class_name": "BasicClusterHandler", + "generic_id": "cluster_handler_0x0000", + "endpoint_id": 1, + "cluster": { + "id": 0, + "name": "Basic", + "type": "server" + }, + "id": "1:0x0000", + "unique_id": "ab:cd:ef:12:02:78:f7:ef:1:0x0000", + "status": "INITIALIZED", + "value_attribute": null + } + ], + "device_ieee": "ab:cd:ef:12:02:78:f7:ef", + "endpoint_id": 1, + "available": true, + "group_id": null, + "suggested_display_precision": null, + "unit": null + }, + "state": { + "class_name": "LQISensor", + "available": true, + "state": 132 + } + }, + { + "info_object": { + "fallback_name": null, + "unique_id": "ab:cd:ef:12:02:78:f7:ef-1-0-rssi", + "migrate_unique_ids": [], + "platform": "sensor", + "class_name": "RSSISensor", + "translation_key": "rssi", + "translation_placeholders": null, + "device_class": "signal_strength", + "state_class": "measurement", + "entity_category": "diagnostic", + "entity_registry_enabled_default": false, + "enabled": true, + "primary": false, + "cluster_handlers": [ + { + "class_name": "BasicClusterHandler", + "generic_id": "cluster_handler_0x0000", + "endpoint_id": 1, + "cluster": { + "id": 0, + "name": "Basic", + "type": "server" + }, + "id": "1:0x0000", + "unique_id": "ab:cd:ef:12:02:78:f7:ef:1:0x0000", + "status": "INITIALIZED", + "value_attribute": null + } + ], + "device_ieee": "ab:cd:ef:12:02:78:f7:ef", + "endpoint_id": 1, + "available": true, + "group_id": null, + "suggested_display_precision": null, + "unit": "dBm" + }, + "state": { + "class_name": "RSSISensor", + "available": true, + "state": -67 + } + } + ], + "update": [ + { + "info_object": { + "fallback_name": null, + "unique_id": "ab:cd:ef:12:02:78:f7:ef-1-25-firmware_update", + "migrate_unique_ids": [], + "platform": "update", + "class_name": "FirmwareUpdateEntity", + "translation_key": null, + "translation_placeholders": null, + "device_class": "firmware", + "state_class": null, + "entity_category": "config", + "entity_registry_enabled_default": true, + "enabled": true, + "primary": false, + "cluster_handlers": [ + { + "class_name": "OtaClientClusterHandler", + "generic_id": "cluster_handler_0x0019_client", + "endpoint_id": 1, + "cluster": { + "id": 25, + "name": "Ota", + "type": "client" + }, + "id": "1:0x0019_client", + "unique_id": "ab:cd:ef:12:02:78:f7:ef:1:0x0019_CLIENT", + "status": "INITIALIZED", + "value_attribute": null + } + ], + "device_ieee": "ab:cd:ef:12:02:78:f7:ef", + "endpoint_id": 1, + "available": true, + "group_id": null, + "supported_features": 7 + }, + "state": { + "class_name": "FirmwareUpdateEntity", + "available": true, + "installed_version": "0x00000040", + "in_progress": false, + "update_percentage": null, + "latest_version": null, + "release_summary": null, + "release_notes": null, + "release_url": null + } + } + ] + }, + "neighbors": [], + "routes": [] +} \ No newline at end of file diff --git a/zha/application/platforms/light/__init__.py b/zha/application/platforms/light/__init__.py index 2bb5e6bd9..c1d86fc70 100644 --- a/zha/application/platforms/light/__init__.py +++ b/zha/application/platforms/light/__init__.py @@ -48,6 +48,8 @@ ATTR_SUPPORTED_COLOR_MODES, ATTR_SUPPORTED_FEATURES, ATTR_XY_COLOR, + COLOR_PROFILE_DEVICE_TYPES, + COLOR_TEMP_ONLY_PROFILE_DEVICE_TYPES, DEFAULT_EXTRA_TRANSITION_DELAY_LONG, DEFAULT_EXTRA_TRANSITION_DELAY_SHORT, DEFAULT_LONG_TRANSITION_TIME, @@ -892,14 +894,19 @@ def recompute_capabilities(self) -> None: super().recompute_capabilities() effect_list = [EFFECT_OFF] + device_type = ( + self.endpoint.zigpy_endpoint.profile_id, + self.endpoint.zigpy_endpoint.device_type, + ) self._internal_supported_color_modes = {ColorMode.ONOFF} + if self._level_cluster_handler: self._internal_supported_color_modes.add(ColorMode.BRIGHTNESS) self._supported_features |= LightEntityFeature.TRANSITION self._brightness = self._level_cluster_handler.current_level - if self._color_cluster_handler: + if device_type in COLOR_PROFILE_DEVICE_TYPES and self._color_cluster_handler: self._min_mireds: int = self._color_cluster_handler.min_mireds self._max_mireds: int = self._color_cluster_handler.max_mireds @@ -907,20 +914,25 @@ def recompute_capabilities(self) -> None: self._internal_supported_color_modes.add(ColorMode.COLOR_TEMP) self._color_temp = self._color_cluster_handler.color_temperature - if self._color_cluster_handler.xy_supported: - self._internal_supported_color_modes.add(ColorMode.XY) - curr_x = self._color_cluster_handler.current_x - curr_y = self._color_cluster_handler.current_y - if curr_x is not None and curr_y is not None: - self._xy_color = (curr_x / 65535, curr_y / 65535) - else: - self._xy_color = (0, 0) + # Even if a device has a `Color` cluster with extra supported color modes, + # we should respect the endpoint device type + if device_type not in COLOR_TEMP_ONLY_PROFILE_DEVICE_TYPES: + if self._color_cluster_handler.xy_supported: + self._internal_supported_color_modes.add(ColorMode.XY) - if self._color_cluster_handler.color_loop_supported: - self._supported_features |= LightEntityFeature.EFFECT - effect_list.append(EFFECT_COLORLOOP) - if self._color_cluster_handler.color_loop_active == 1: - self._effect = EFFECT_COLORLOOP + curr_x = self._color_cluster_handler.current_x + curr_y = self._color_cluster_handler.current_y + + if curr_x is not None and curr_y is not None: + self._xy_color = (curr_x / 65535, curr_y / 65535) + else: + self._xy_color = (0, 0) + + if self._color_cluster_handler.color_loop_supported: + self._supported_features |= LightEntityFeature.EFFECT + effect_list.append(EFFECT_COLORLOOP) + if self._color_cluster_handler.color_loop_active == 1: + self._effect = EFFECT_COLORLOOP self._supported_color_modes = supported_color_modes = ( filter_supported_color_modes(self._internal_supported_color_modes) @@ -1086,13 +1098,23 @@ async def async_update(self) -> None: if (color_mode := results.get("color_mode")) is not None: if color_mode == Color.ColorMode.Color_temperature: - self._color_mode = ColorMode.COLOR_TEMP + new_color_mode = ColorMode.COLOR_TEMP + else: + new_color_mode = ColorMode.XY + + # Only apply the reported color mode if it is actually + # supported. Buggy firmware (e.g. Tuya CCT bulbs) can + # report a ZCL color_mode that doesn't match the device's + # capabilities—don't let that override the correct state. + if new_color_mode in self._supported_color_modes: + self._color_mode = new_color_mode + + if self._color_mode == ColorMode.COLOR_TEMP: color_temp = results.get("color_temperature") - if color_temp is not None and color_mode: + if color_temp is not None: self._color_temp = color_temp self._xy_color = None - else: - self._color_mode = ColorMode.XY + elif self._color_mode == ColorMode.XY: color_x = results.get("current_x") color_y = results.get("current_y") if color_x is not None and color_y is not None: diff --git a/zha/application/platforms/light/const.py b/zha/application/platforms/light/const.py index 69488cc86..46405ef5d 100644 --- a/zha/application/platforms/light/const.py +++ b/zha/application/platforms/light/const.py @@ -110,3 +110,28 @@ class FlashMode(StrEnum): (zll.PROFILE_ID, zll.DeviceType.ON_OFF_LIGHT), } ) + +# For device types not in this set, the Color Control cluster should be ignored even if +# it is present on the endpoint (e.g. a DIMMABLE_LIGHT with a spurious Color Control +# cluster should not gain color modes). +COLOR_PROFILE_DEVICE_TYPES: frozenset[tuple[int, int]] = frozenset( + { + # ZHA + (zha.PROFILE_ID, zha.DeviceType.COLOR_DIMMABLE_LIGHT), + (zha.PROFILE_ID, zha.DeviceType.COLOR_TEMPERATURE_LIGHT), + (zha.PROFILE_ID, zha.DeviceType.EXTENDED_COLOR_LIGHT), + # ZLL + (zll.PROFILE_ID, zll.DeviceType.COLOR_LIGHT), + (zll.PROFILE_ID, zll.DeviceType.COLOR_TEMPERATURE_LIGHT), + (zll.PROFILE_ID, zll.DeviceType.EXTENDED_COLOR_LIGHT), + } +) + +# The spec mandates ColorCapabilities SHALL be 0x0010 (`Color_temperature`) for these. +# XY and hue/saturation must not be exposed even if the device reports them. +COLOR_TEMP_ONLY_PROFILE_DEVICE_TYPES: frozenset[tuple[int, int]] = frozenset( + { + (zha.PROFILE_ID, zha.DeviceType.COLOR_TEMPERATURE_LIGHT), + (zll.PROFILE_ID, zll.DeviceType.COLOR_TEMPERATURE_LIGHT), + } +)