Collection of custom ESPHome firmware and hardware projects for Levoit air purifiers, eliminating cloud dependency and enabling native Home Assistant integration.
The Core and Vital Series share quite a lot on the protocol level, while having some differences based on model and MCU version. This is an external ESPHome component that supports all (WIP!) Core and Vital Air Purifiers.
Can be flashed to the original ESP32-SOLO-C1 or also installed on top (replace original), check 'Installation'
Requires: ESPHome 2026.01.2+
| Model | MCU Version | Status |
|---|---|---|
| Levoit Core 200s | 2.0.11 | ✅ Tested |
| Levoit Core 300s | 2.0.7, 2.0.11 | ✅ Tested |
| Levoit Core 400s | 3.0.0 | ✅ Tested |
| Levoit Core 600s | 2.0.1 | ✅ Tested |
| Levoit Vital 100s | 1.0.5 | ✅ Tested |
| Levoit Vital 200s (Pro) | 1.0.5 | ✅ Tested |
| Levoit Sprout | 1.0.5 | ✅ Tested (!) WIP |
- Levoit LV PUR 131s – Custom Firmware + MCU & sensor upgrade + hardware hack
- Levoit Mini – Custom PCB, 3D parts, hardware hack
Core200s
Core300s - with Air Quality and Auto
Native Home Assistant Fan component, with preset support. Available speed levels and presets are based on model.
| Model | Speed Levels | Preset Modes |
|---|---|---|
| C200S | 1–3 | Manual, Sleep |
| C300S | 1–3 | Auto, Manual, Sleep |
| C400S | 1–4 | Auto, Manual, Sleep |
| C600S | 1–4 | Auto, Manual, Sleep |
| V100S | 1–4 | Auto, Manual, Sleep, Pet |
| V200S | 1–4 | Auto, Manual, Sleep, Pet |
| Sprout | 1–4 | Auto, Manual |
| Feature | Type | Config Key | Description |
|---|---|---|---|
| Display | switch | display |
Toggle the LED display on/off |
| Child Lock | switch | child_lock |
Disable physical buttons on the device |
| Light Detect | switch | light_detect |
Auto-dim display when ambient light is low Vital Series + Core 600S |
| Night Light | select | nightlight |
Night light brightness: Off / Mid / Full Only Core200S |
| Feature | Type | Config Key | Description |
|---|---|---|---|
| Timer | number | timer |
Run timer in minutes |
| Timer Set | text_sensor | timer_duration_initial |
Originally set timer as readable string (e.g. "2h 30 min") |
| Timer Remaining | text_sensor | timer_duration_remaining |
Time left on active timer (e.g. "1h 15 min") |
| Feature | Type | Config Key | Description |
|---|---|---|---|
| Filter Lifetime | number | filter_lifetime_months |
Expected filter lifespan in months (1–12); used to compute Filter Life % |
| Filter Life Left | sensor | filter_life_left |
Remaining filter life as % ⁽¹⁾ |
| Filter Low | binary_sensor | filter_low |
on when Filter Life % drops below 5% ⁽¹⁾ |
| Current CADR | sensor | current_cadr |
Calculated Clean Air Delivery Rate at current fan speed in m³/h ⁽¹⁾ |
| Reset Filter Stats | button | reset_filter_stats |
Reset cumulative CADR and runtime counters — restores Filter Life % to 100% ⁽¹⁾ |
⁽¹⁾ Computed by the component (not received from MCU), works on all models.
| Feature | Type | Config Key | Description |
|---|---|---|---|
| Auto Mode | select | auto_mode |
Auto mode type — options vary by model (see below) Not for Core200S |
| Auto Mode Room Size | number | efficiency_room_size |
Target room area for efficient auto mode in m² Not for Core200S |
| Efficiency Counter | sensor | efficiency_counter |
Seconds remaining at high fan speed in efficient auto mode Vital only |
| Auto Mode High Fan Time | text_sensor | auto_mode_room_size_high_fan |
Time still running at high speed in efficient auto mode, human readable Vital only |
Auto mode options per model:
| Model | Options | Room Size Range |
|---|---|---|
| C200S | — | up to 40 m² (430 ft²) |
| C300S | Default / Quiet / Room Size | 9–50 m² (97–538 ft²) |
| C400S | Default / Quiet / Room Size | 9–83 m² (97–894 ft²) |
| C600S | Default / Quiet / Room Size / ECO | 9–147 m² (97–1,582 ft²) |
| V100S | Default / Quiet / Efficient | 9–52 m² (97–560 ft²) |
| V200S | Default / Quiet / Efficient | 9–87 m² (97–936 ft²) |
| Sprout | Default / Quiet / Efficient | 9–57 m² (97–936 ft²) |
| Feature | Type | Config Key | Description |
|---|---|---|---|
| PM2.5 | sensor | pm25 |
Particulate matter concentration in µg/m³ from built-in sensor Not for Core200S |
| AQI | sensor | aqi |
Air Quality Index as reported by the MCU Not for Core200S |
| Feature | Type | Config Key | Description |
|---|---|---|---|
| MCU Version | text_sensor | mcu_version |
Firmware version string of the purifier MCU chip |
| ESP Version | text_sensor | esp_version |
ESPHome component version string |
| Error | text_sensor | error_message |
Device error status: "Ok" or "Sensor Error" Not for Core200S |
- Added Levoit Sprout support
- Added Core 600S support: 4 fan speeds, 4 auto modes (Default / Quiet / Room Size / ECO), Light Detect switch, CADR 641 m³/h
- Added Vital 200S (Pro) support: same protocol as Vital 100S, tested with original ESP
- Updated Auto Mode select to show model-specific options (3 for Core/Vital, 4 for Core 600S)
- Added Core200s support and readme / example.
- Renamed/moved repo to tuct/levoit - for easier collaboration with pull requests, ...
- Works with ESPHome 2026.3+
- Sensors - added state class measurement -> allow statistics to be tracked
- The component has been updated for ESPHome 2025.12.5
If you have a Levoit model that isn't supported yet, or a newer MCU firmware on a supported model, a UART dump is the best way to contribute.
What's needed:
- A logic analyzer capture of the UART traffic between the ESP32 and the MCU (both directions)
- The MCU firmware version (visible in the Levoit app or via
mcu_versionsensor once flashed) - A description of any features the device has (fan speeds, auto modes, sensors, lights, etc.)
Open an issue or pull request in the repo with the dump attached.
The ESP32 and MCU communicate over UART at 115200 baud, 8N1. See Levoit UART Protocol Details for a full description of the packet format. To capture traffic:
Check the individual device README for teardown steps, PCB photos, and the exact solder points to use for your model.
-
Open the device and locate the correct solder points — see the individual device README for the exact pads
Note: The debug pin header RX/TX pins are used to flash the ESP32. They are not the UART line between the ESP32 and the MCU. You need to tap into the dedicated ESP↔MCU communication pads (test points or vias near the ESP32), not the header.
-
Connect a logic analyzer to both the ESP TX and MCU TX lines, with a shared GND
-
In Saleae Logic 2, add an Async Serial analyzer on each channel:
- Baud rate:
115200 - Bits per frame:
8 - Stop bits:
1 - No parity
- Baud rate:
-
Power on the device and capture separate, clearly labelled dumps for each action — one action per capture makes it much easier to identify which bytes correspond to which command:
Dump Action bootupPower on → wait until Wi-Fi connected and app shows online speed_1-4_appSwitch through fan speeds 1 → 2 → 3 → 4 via the app speed_1-4_deviceSwitch through fan speeds 1 → 2 → 3 → 4 via the physical buttons mode_appSwitch through all modes (Manual / Auto / Sleep / Pet) via the app mode_deviceSwitch through all modes via the physical buttons auto_modeSwitch through all auto mode sub-options (Default / Quiet / Room Size / etc.) display_on_offToggle the display on and off child_lockEnable and disable child lock timerSet a timer via the app filter_resetReset filter stats (model-specific) Any unique features: lights, white noise, CO₂ sensor, etc. Label each file clearly (e.g.
core300s_2.0.11_speed_app.txt).Example: See
devices/levoit-sprout/uart/uart_dumpsfor a real Sprout dump covering boot, speed switching, light modes, and white noise — each section labelled with the action performed. -
In Logic 2, use Export Data → export the analyzer results as a text/CSV file (not the
.salsession). A plain text file with the decoded HLA output is all that's needed.
A High-Level Analyzer for the Levoit UART protocol is included in logic2/levoit_uart/.
Install:
- Open Logic 2 → Extensions (puzzle icon) → Load Existing Extension
- Select the
logic2/levoit_uart/folder
Use:
- Add an Async Serial analyzer on the ESP TX channel (115200 baud, 8N1) — this is ESP→MCU traffic
- Add a second Async Serial analyzer on the MCU TX channel — this is MCU→ESP traffic
- Add a Levoit UART Extractor HLA on top of the first Async Serial, set Channel to
ESP->MCU - Add a second Levoit UART Extractor HLA on top of the second Async Serial, set Channel to
MCU->ESP - Decoded packets appear as:
[MCU->ESP] RESP(0x52) | CMD=01 40 41 | PAY=00 01 ...
Both HLAs run side by side so you can see the full request/response exchange in one view.
See logic2/levoit_uart/README.md for full details.
Not my projects, but worth checking out:




