Skip to content

fix: purifier light detection and display guards used the wrong state - #551

Open
ryan-ronnander wants to merge 1 commit into
webdjoe:devfrom
ryan-ronnander:fix-light-detection-guard
Open

ryan-ronnander wants to merge 1 commit into
webdjoe:devfrom
ryan-ronnander:fix-light-detection-guard

Conversation

@ryan-ronnander

@ryan-ronnander ryan-ronnander commented Sep 23, 2026 •

Copy link
Copy Markdown

Why

This started with the display switch in Home Assistant failing on my Vital 200S, while the VeSync app changed the same setting without complaint:

ERROR [pyvesync.devices.vesyncpurifier] Cannot set display when light detection is enabled
ERROR [homeassistant.components.websocket_api.http.connection] Error during service call to switch.turn_off: Success

Follow-up to #351. The two guards it added check light_detection_status (whether the room is dark right now) where they mean light_detection_switch (whether the feature is enabled). On a Levoit Vital 200S (LAP-V201S-WUS), that makes light detection and the display unreliable to control through pyvesync, and so through Home Assistant too. I'm preparing a Home Assistant VeSync change that adds a light detection switch and a dark room sensor for these purifiers. With the current guards, that switch silently does nothing when turned on in a dark room, and the existing display switch fails whenever the room is dark.

  • toggle_light_detection checked light_detection_status (whether the room is dark right now) where it meant light_detection_switch (whether the feature is enabled). Turning light detection on in a dark room, or off in a lit room, returned True without calling the API.
  • toggle_display refused whenever light_detection_status was on, which is the same wrong field. As a result the display switch in HA failed with "Cannot set display when light detection is enabled" depending on how bright the room was.

Fix

  • toggle_light_detection compares against light_detection_switch.
  • The display guard in toggle_display now applies only to the Vital 100S (LAP-V102S), and checks light_detection_switch. The Vital 200S accepts setDisplay with light detection enabled, and the VeSync app lets you change both settings at any time. The display setting is the master: with light detection on, the device only darkens a display that is set to on while the room is dark.

I kept the guard for the Vital 100S because #351 reported 11017000 BYPASS_NOT_SUPPORTED there, and I don't own a 100S to check. If someone with a 100S finds that it accepts the call, the guard can go.

Only VeSyncAirBaseV2 changes (Vital 100S/200S, Everest Air, Sprout). The Core series and the other purifier classes are untouched.

Real-hardware verification

  • Tested on the physical device.
    • Model: LAP-V201S-WUS (Vital 200S)
    • Firmware version: 1.0.16
  • Not applicable (explain why): ____
  • I do not own the device; a packet capture is provided / the device has been shared with a maintainer for verification.

A script called this branch's methods directly through pyvesync (Python 3.13), not through Home Assistant, with the purifier running and the room lit. Each call returned code 0, and each change was confirmed by a later update().

Step Expected Result
Light detection on light_detection_switch on on ✅
Display off, light detection on display_set_status off off ✅
Display on, light detection on display_set_status on on ✅
Light detection off, room lit (3.4.2 skips the API call here) light_detection_switch off off ✅

Tests

TestAirBaseV2Guards in test_purifiers.py:

  • light detection toggles call the API for every combination of switch and room reading
  • light detection that is already set skips the API
  • toggling with no argument flips the light detection switch, whatever the room reading
  • the display toggles with light detection on
  • the Vital 100S refuses the display only when the light detection switch is on, whatever the room reading

Type of change

  • Bug fix (fix:)
  • New feature or device support (feat:)
  • Documentation (docs:)
  • Refactor / test / chore (no functional change)

Checklist

  • This PR is a single feature, fix, or edit (not a bundle of unrelated changes).
  • The change follows the intended architecture (base class → device + API mixin → device map; state in DeviceState; models in models/; constants in pyvesync.const).
  • No API request/response fields were invented — all come from a real packet capture.
  • ruff check, pylint, mypy, and pytest pass locally.
  • Tests added/updated and API fixtures written (pytest --write_api) where relevant.
  • Documentation updated if behavior or public API changed.

Checked on this branch merged onto current dev. mypy reports the two errors in vesyncthermostat.py that dev already has; this PR doesn't touch that file. No docs describe these guards, and no new API calls were added, so there are no new fixtures.

@ryan-ronnander

Copy link
Copy Markdown
Author

@webdjoe could you take a look at this when you get a chance? home-assistant/core#183015 (light detection switch and dark room sensor for the Vital 200S) is blocked on it.

I've updated the description to the new PR template, including a direct pyvesync test on the device that the new contribution rules ask for. Once this is in a release, I can request a pyvesync version bump in HA core as its own PR and take #183015 out of draft.

Thanks.

@webdjoe webdjoe added bug Something isn't working next labels Nov 1, 2026
- toggle_light_detection compared the requested state against
  light_detection_status (the dark/lit sensor reading) instead of
  light_detection_switch (the feature toggle), so enabling it in a dark room
  or disabling it in a lit room returned early without calling the API.
- toggle_display refused whenever the room was dark, on every model. The
  Vital 200S accepts setDisplay with light detection on, so the guard now
  applies only to the Vital 100S (the 11017000 report in webdjoe#351) and checks
  light_detection_switch.
- Add tests for both guards.
- Verified on a Levoit Vital 200S (LAP-V201S-WUS).
@webdjoe
webdjoe force-pushed the fix-light-detection-guard branch from 31b1340 to 4996643 Compare November 5, 2026 04:22
@webdjoe

webdjoe commented Nov 5, 2026

Copy link
Copy Markdown
Owner

Looking back on #351, it should not have been merged. This library cannot guard against all conditions, it just add unnecessary logic that needs to be maintained for situations like this. I think the best solution is to remove the condition entirely and leave it up to the user to know when it's appropriate to make the request.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working followup next

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants