Skip to content

Commit 4ee9876

Browse files
committed
Add color mode support for Xiaomi light devices
- Introduced a new capability for handling color modes in light devices. - Updated device specifications to include color mode properties and commands. - Enhanced profile detection logic to support color functionality based on device capabilities. - Implemented event emission for color mode changes and added support for color temperature ranges.
1 parent 362a0dc commit 4ee9876

File tree

8 files changed

+431
-15
lines changed

8 files changed

+431
-15
lines changed
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
{
2+
"id": "summerdetail20801.colorMode",
3+
"version": 1,
4+
"status": "proposed",
5+
"name": "Color Mode",
6+
"ephemeral": false,
7+
"attributes": {
8+
"colorMode": {
9+
"schema": {
10+
"type": "object",
11+
"properties": {
12+
"value": {
13+
"title": "ColorMode",
14+
"type": "string",
15+
"enum": [
16+
"day",
17+
"night",
18+
"color"
19+
]
20+
},
21+
"data": {
22+
"type": "object",
23+
"additionalProperties": false,
24+
"required": [],
25+
"properties": {
26+
"supportedColorModes": {
27+
"type": "array",
28+
"items": {
29+
"title": "ColorMode",
30+
"type": "string",
31+
"enum": [
32+
"day",
33+
"night",
34+
"color"
35+
]
36+
}
37+
}
38+
}
39+
}
40+
},
41+
"additionalProperties": false,
42+
"required": [
43+
"value"
44+
]
45+
},
46+
"setter": "setColorMode",
47+
"enumCommands": [
48+
{
49+
"command": "day",
50+
"value": "day"
51+
},
52+
{
53+
"command": "night",
54+
"value": "night"
55+
},
56+
{
57+
"command": "color",
58+
"value": "color"
59+
}
60+
]
61+
},
62+
"supportedColorModes": {
63+
"schema": {
64+
"type": "object",
65+
"properties": {
66+
"value": {
67+
"type": "array",
68+
"items": {
69+
"title": "ColorMode",
70+
"type": "string",
71+
"enum": [
72+
"day",
73+
"night",
74+
"color"
75+
]
76+
}
77+
}
78+
},
79+
"additionalProperties": false,
80+
"required": []
81+
},
82+
"enumCommands": []
83+
}
84+
},
85+
"commands": {
86+
"day": {
87+
"arguments": [],
88+
"name": "day",
89+
"sensitive": false
90+
},
91+
"night": {
92+
"arguments": [],
93+
"name": "night",
94+
"sensitive": false
95+
},
96+
"color": {
97+
"arguments": [],
98+
"name": "color",
99+
"sensitive": false
100+
},
101+
"setColorMode": {
102+
"name": "setColorMode",
103+
"arguments": [
104+
{
105+
"name": "mode",
106+
"optional": false,
107+
"schema": {
108+
"title": "ColorMode",
109+
"type": "string",
110+
"enum": [
111+
"day",
112+
"night",
113+
"color"
114+
]
115+
}
116+
}
117+
],
118+
"sensitive": false
119+
}
120+
}
121+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
{
2+
"detailView": [
3+
{
4+
"label": "Color Mode",
5+
"displayType": "list",
6+
"list": {
7+
"command": {
8+
"name": "setColorMode",
9+
"alternatives": [
10+
{
11+
"key": "day",
12+
"value": "Day",
13+
"type": "active"
14+
},
15+
{
16+
"key": "night",
17+
"value": "Night",
18+
"type": "active"
19+
},
20+
{
21+
"key": "color",
22+
"value": "Color",
23+
"type": "active"
24+
}
25+
],
26+
"supportedValues": "supportedColorModes.value"
27+
},
28+
"state": {
29+
"value": "colorMode.value",
30+
"alternatives": [
31+
{
32+
"key": "day",
33+
"value": "Day",
34+
"type": "active"
35+
},
36+
{
37+
"key": "night",
38+
"value": "Night",
39+
"type": "active"
40+
},
41+
{
42+
"key": "color",
43+
"value": "Color",
44+
"type": "active"
45+
}
46+
]
47+
}
48+
}
49+
}
50+
],
51+
"automation": {
52+
"conditions": [
53+
{
54+
"label": "Color Mode",
55+
"displayType": "list",
56+
"list": {
57+
"alternatives": [
58+
{
59+
"key": "day",
60+
"value": "Day",
61+
"type": "active"
62+
},
63+
{
64+
"key": "night",
65+
"value": "Night",
66+
"type": "active"
67+
},
68+
{
69+
"key": "color",
70+
"value": "Color",
71+
"type": "active"
72+
}
73+
],
74+
"supportedValues": "supportedColorModes.value",
75+
"value": "colorMode.value",
76+
"multiSelectable": false
77+
}
78+
}
79+
],
80+
"actions": [
81+
{
82+
"label": "Set Color Mode",
83+
"displayType": "list",
84+
"list": {
85+
"alternatives": [
86+
{
87+
"key": "day",
88+
"value": "Day",
89+
"type": "active"
90+
},
91+
{
92+
"key": "night",
93+
"value": "Night",
94+
"type": "active"
95+
},
96+
{
97+
"key": "color",
98+
"value": "Color",
99+
"type": "active"
100+
}
101+
],
102+
"supportedValues": "supportedColorModes.value",
103+
"command": "setColorMode"
104+
}
105+
}
106+
]
107+
},
108+
"id": "summerdetail20801.colorMode",
109+
"version": 1
110+
}

xiaomi-miot/profiles/xiaomi-light-color.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ components:
1212
version: 1
1313
- id: refresh
1414
version: 1
15+
- id: summerdetail20801.colorMode
16+
version: 1
1517
categories:
1618
- name: Light
1719
preferences:

xiaomi-miot/src/capability_handlers.lua

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -900,4 +900,84 @@ function M.handle_air_purifier_mode(driver, device, command)
900900
end
901901
end
902902

903+
function M.handle_color_mode(driver, device, command)
904+
log.info(string.format("Set color mode to %s for %s", command.args.mode, device.label))
905+
906+
local device_data = get_device_data(device)
907+
local spec = get_device_spec(device)
908+
909+
if not spec then
910+
log.warn("Device spec not found")
911+
return
912+
end
913+
914+
if not spec.mode_map then
915+
log.warn("Device does not have mode_map defined")
916+
return
917+
end
918+
919+
local color_mode_capability = capabilities["summerdetail20801.colorMode"]
920+
921+
-- Find the mode value from mode_map (reverse lookup)
922+
local mode_value = nil
923+
for value, mode_name in pairs(spec.mode_map) do
924+
if mode_name == command.args.mode then
925+
mode_value = value
926+
break
927+
end
928+
end
929+
930+
if not mode_value then
931+
log.error(string.format("Invalid color mode: %s", command.args.mode))
932+
return
933+
end
934+
935+
local protocol_type = get_protocol_type(device, spec)
936+
local success = false
937+
938+
if protocol_type == "miio" then
939+
-- MiIO protocol: use command
940+
if not spec.commands or not spec.commands.set_color_mode then
941+
log.warn("MiIO device does not define commands.set_color_mode")
942+
return
943+
end
944+
945+
local protocol = get_protocol(device, spec)
946+
local cmd = spec.commands.set_color_mode
947+
local params = {}
948+
949+
if cmd.param_key then
950+
params = { mode_value }
951+
else
952+
params = cmd.params or {}
953+
end
954+
955+
local result = protocol:send_raw(device_data.ip, device_data.token, cmd.method, params)
956+
success = result ~= nil
957+
else
958+
-- MIOT protocol: use property
959+
if not spec.properties or not spec.properties.mode then
960+
log.warn("Device does not support mode property")
961+
return
962+
end
963+
964+
local protocol = get_protocol(device, spec)
965+
local prop = spec.properties.mode
966+
967+
success = protocol:set_property(
968+
device_data.ip,
969+
device_data.token,
970+
prop.siid,
971+
prop.piid,
972+
mode_value
973+
)
974+
end
975+
976+
if success then
977+
device:emit_event(color_mode_capability.colorMode(command.args.mode))
978+
else
979+
log.error("Failed to set color mode")
980+
end
981+
end
982+
903983
return M

xiaomi-miot/src/device_models.lua

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,16 +1192,41 @@ M.DEVICE_SPECS = {
11921192
},
11931193
["yeelink.light.strip1"] = {
11941194
device_type = "light",
1195-
properties = {
1196-
brightness = { siid = 2, piid = 2, min = 1, max = 100, step = 1, unit = "percentage" },
1197-
color = { siid = 2, piid = 3, min = 1, max = 16777215, step = 1, unit = "rgb" },
1198-
color_temperature = { siid = 2, piid = 4, min = 1700, max = 6500, step = 1, unit = "kelvin" },
1199-
mode = { siid = 2, piid = 5 },
1200-
power = { siid = 2, piid = 1 }
1195+
status_properties = {
1196+
"power",
1197+
"bright",
1198+
"color_mode",
1199+
"rgb",
1200+
"hue",
1201+
"sat",
1202+
"ct",
1203+
},
1204+
property_map = {
1205+
power = "power",
1206+
bright = "brightness",
1207+
color_mode = "color_mode_raw",
1208+
rgb = "rgb",
1209+
hue = "hue",
1210+
sat = "sat",
1211+
ct = "color_temperature",
12011212
},
12021213
mode_map = {
12031214
[1] = "color",
12041215
[2] = "day"
1216+
},
1217+
color_temperature_range = {
1218+
min = 1700,
1219+
max = 6500,
1220+
step = 1,
1221+
},
1222+
commands = {
1223+
power_on = { method = "set_power", params = { "on" } },
1224+
power_off = { method = "set_power", params = { "off" } },
1225+
set_brightness = { method = "set_bright", param_key = "brightness" },
1226+
set_rgb_int = { method = "set_rgb", param_key = "rgb" },
1227+
set_color_temperature = { method = "set_ct_abx", param_key = "color_temperature" },
1228+
set_hsv = { method = "set_hsv", param_key = "hsv" },
1229+
set_color_mode = { method = "set_scene", param_key = "mode" },
12051230
}
12061231
},
12071232
["yeelink.light.strip2"] = {
@@ -5017,11 +5042,11 @@ M.DEVICE_SPECS = {
50175042
"mode",
50185043
},
50195044
property_map = {
5020-
power = "power",
5021-
humidity = "humidity",
5022-
temp_dec = "temp_dec",
5023-
limit_hum = "target_humidity",
5024-
mode = "mode_raw",
5045+
power = "power",
5046+
humidity = "humidity",
5047+
temp_dec = "temp_dec",
5048+
limit_hum = "target_humidity",
5049+
mode = "mode_raw",
50255050
},
50265051
mode_map = {
50275052
[0] = "auto",

0 commit comments

Comments
 (0)