Skip to content

Commit 0761a95

Browse files
committed
Add RGB nightlight support for VeSyncHumid200300S device
1 parent 2f2511f commit 0761a95

7 files changed

Lines changed: 449 additions & 2 deletions

File tree

.claude/settings.local.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"permissions": {
3+
"allow": [
4+
"Bash(dir /s /b \"C:\\\\temp\\\\vesync\\\\dump\\\\*Humidifier*\")",
5+
"Bash(xargs cat:*)",
6+
"Bash(python:*)",
7+
"Bash(git reset:*)",
8+
"Bash(git commit:*)",
9+
"Bash(git push:*)",
10+
"Bash(pre-commit run:*)",
11+
"Bash(pip install:*)",
12+
"Bash(git add:*)",
13+
"Bash(git show:*)"
14+
]
15+
}
16+
}

log.json

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
2026-01-21 15:54:30.942 DEBUG (MainThread) [pyvesync.vesync] ==================API CALL==================
2+
Caller: VeSyncHumid200300S.call_bypassv2_api [devices.vesynchumidifier]
3+
API CALL to endpoint: /cloud/v2/deviceManaged/bypassV2
4+
Host: smartapi.vesync.eu
5+
Full URL: https://smartapi.vesync.eu/cloud/v2/deviceManaged/bypassV2
6+
Response Status: 200
7+
Method: POST
8+
---------------Request-----------------
9+
Request Headers:
10+
{
11+
"Content-Type": "application/json; charset=UTF-8",
12+
"User-Agent": "okhttp/3.12.1"
13+
}
14+
Request Body:
15+
{
16+
"acceptLanguage": "en",
17+
"accountID": "##_REDACTED_##",
18+
"appVersion": "5.6.60",
19+
"cid": "##_REDACTED_##",
20+
"configModule": "WFON_AHM_LUH-A451S-WEU_EU",
21+
"debugMode": false,
22+
"method": "bypassV2",
23+
"phoneBrand": "pyvesync",
24+
"phoneOS": "Android",
25+
"traceId": "1769007201",
26+
"timeZone": "Europe/Berlin",
27+
"token": "##_REDACTED_##",
28+
"userCountryCode": "CZ",
29+
"deviceId": "vsaq338779044488d9c68c79a2ef33ab",
30+
"configModel": "WFON_AHM_LUH-A451S-WEU_EU",
31+
"payload": {
32+
"data": {},
33+
"method": "getHumidifierStatus",
34+
"source": "APP"
35+
}
36+
}
37+
---------------Response-----------------
38+
Response Headers:
39+
{
40+
"Date": "Wed, 21 Jan 2026 14:54:30 GMT",
41+
"Content-Type": "application/json;charset=UTF-8",
42+
"Transfer-Encoding": "chunked",
43+
"Connection": "keep-alive",
44+
"Content-Encoding": "gzip"
45+
}
46+
Response Body:
47+
{
48+
"traceId": "1769007201",
49+
"code": 0,
50+
"msg": "request success",
51+
"module": null,
52+
"stacktrace": null,
53+
"result": {
54+
"traceId": "1769007201",
55+
"code": 0,
56+
"result": {
57+
"enabled": true,
58+
"mist_virtual_level": 5,
59+
"mist_level": 2,
60+
"mode": "auto",
61+
"water_lacks": false,
62+
"water_tank_lifted": false,
63+
"humidity": 46,
64+
"humidity_high": false,
65+
"display": true,
66+
"warm_enabled": false,
67+
"warm_level": 0,
68+
"automatic_stop_reach_target": false,
69+
"configuration": {
70+
"auto_target_humidity": 55,
71+
"display": true,
72+
"automatic_stop": true
73+
},
74+
"extension": {
75+
"schedule_count": 0,
76+
"timer_remain": 0
77+
},
78+
"rgbNightLight": {
79+
"action": "on",
80+
"colorMode": "color",
81+
"speed": 0,
82+
"brightness": 93,
83+
"red": 178,
84+
"green": 98,
85+
"blue": 0,
86+
"colorSliderLocation": 81
87+
}
88+
}
89+
}
90+
}
91+
2026-01-21 15:54:30.943 DEBUG (MainThread) [pyvesync.devices.vesynchumidifier] OasisMist™ 4.5L for LUH-O451S-WEU API from get_details returned code: 0, message: Success

src/pyvesync/base_devices/humidifier_base.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ class HumidifierState(DeviceState):
7676
'nightlight_brightness',
7777
'nightlight_color_temp',
7878
'nightlight_status',
79+
'rgb_nightlight_blue',
80+
'rgb_nightlight_brightness',
81+
'rgb_nightlight_color_mode',
82+
'rgb_nightlight_green',
83+
'rgb_nightlight_red',
84+
'rgb_nightlight_set_time',
85+
'rgb_nightlight_status',
7986
'temperature',
8087
'warm_mist_enabled',
8188
'warm_mist_level',
@@ -112,6 +119,13 @@ def __init__(
112119
self.mode: str | None = None
113120
self.nightlight_brightness: int | None = None
114121
self.nightlight_status: str | None = None
122+
self.rgb_nightlight_status: str | None = None
123+
self.rgb_nightlight_brightness: int | None = None
124+
self.rgb_nightlight_red: int | None = None
125+
self.rgb_nightlight_green: int | None = None
126+
self.rgb_nightlight_blue: int | None = None
127+
self.rgb_nightlight_color_mode: str | None = None
128+
self.rgb_nightlight_set_time: float | None = None
115129
self.nightlight_color_temp: int | None = None
116130
self.warm_mist_enabled: bool | None = None
117131
self.warm_mist_level: int | None = None
@@ -289,6 +303,15 @@ def supports_nightlight_brightness(self) -> bool:
289303
"""Return True if the humidifier supports nightlight brightness."""
290304
return HumidifierFeatures.NIGHTLIGHT_BRIGHTNESS in self.features
291305

306+
@property
307+
def supports_rgb_nightlight(self) -> bool:
308+
"""Return True if the humidifier supports RGB nightlight.
309+
310+
Returns:
311+
bool: True if RGB nightlight is supported, False otherwise.
312+
"""
313+
return HumidifierFeatures.RGB_NIGHTLIGHT in self.features
314+
292315
@property
293316
def supports_drying_mode(self) -> bool:
294317
"""Return True if the humidifier supports drying mode."""
@@ -461,6 +484,33 @@ async def toggle_nightlight(self, toggle: bool | None = None) -> bool:
461484
logger.error('Nightlight has not been configured.')
462485
return False
463486

487+
async def set_rgb_nightlight(
488+
self,
489+
power: bool | None = None,
490+
brightness: int | None = None,
491+
red: int | None = None,
492+
green: int | None = None,
493+
blue: int | None = None,
494+
) -> bool:
495+
"""Set RGB nightlight state and color.
496+
497+
Args:
498+
power: Turn nightlight on (True) or off (False).
499+
brightness: Brightness level (0-100).
500+
red: Red color value (0-255).
501+
green: Green color value (0-255).
502+
blue: Blue color value (0-255).
503+
504+
Returns:
505+
bool: Success of request.
506+
"""
507+
del power, brightness, red, green, blue
508+
if not self.supports_rgb_nightlight:
509+
logger.error('RGB Nightlight is not supported for this device.')
510+
return False
511+
logger.error('RGB Nightlight has not been configured.')
512+
return False
513+
464514
async def set_warm_level(self, warm_level: int) -> bool:
465515
"""Set Humidifier Warm Level.
466516

src/pyvesync/const.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,7 @@ class HumidifierFeatures(Features):
497497
WARM_MIST: Warm mist status.
498498
AUTO_STOP: Auto stop when target humidity is reached.
499499
Different from auto, which adjusts fan level to maintain humidity.
500+
RGB_NIGHTLIGHT: RGB nightlight with color control.
500501
"""
501502

502503
ONOFF = 'onoff'
@@ -507,6 +508,7 @@ class HumidifierFeatures(Features):
507508
AUTO_STOP = 'auto_stop'
508509
NIGHTLIGHT_BRIGHTNESS = 'nightlight_brightness'
509510
DRYING_MODE = 'drying_mode'
511+
RGB_NIGHTLIGHT = 'rgb_nightlight'
510512

511513

512514
class PurifierFeatures(Features):

src/pyvesync/device_map.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -684,7 +684,11 @@ class ThermostatMap(DeviceMapTemplate):
684684
HumidifierMap(
685685
class_name='VeSyncHumid200300S',
686686
dev_types=['LUH-O451S-WEU'],
687-
features=[HumidifierFeatures.WARM_MIST, HumidifierFeatures.AUTO_STOP],
687+
features=[
688+
HumidifierFeatures.WARM_MIST,
689+
HumidifierFeatures.AUTO_STOP,
690+
HumidifierFeatures.RGB_NIGHTLIGHT,
691+
],
688692
mist_modes={
689693
HumidifierModes.AUTO: 'auto',
690694
HumidifierModes.SLEEP: 'sleep',

0 commit comments

Comments
 (0)