From 4d8e59cd922b0b1be1efe9718fbd0eab6386071d Mon Sep 17 00:00:00 2001 From: edennelson Date: Tue, 30 Jun 2026 14:22:07 -0700 Subject: [PATCH 1/2] Add fan operating mode select --- README.md | 2 + components/levoit/fan/levoit_fan.cpp | 4 ++ components/levoit/levoit.cpp | 42 +++++++++++++++++++ components/levoit/select/__init__.py | 1 + components/levoit/select/levoit_select.cpp | 32 ++++++++++++++ components/levoit/types.h | 2 + devices/levoit-core200s/common.yaml | 4 ++ .../levoit-core200s-builder-c3.yaml | 4 ++ .../levoit-core200s-builder-s3.yaml | 4 ++ .../levoit-core200s-builder.yaml | 4 ++ devices/levoit-core300s/common.yaml | 4 ++ .../levoit-core300s-builder-c3.yaml | 4 ++ .../levoit-core300s-builder-s3.yaml | 4 ++ .../levoit-core300s-builder.yaml | 4 ++ devices/levoit-core400s/README.md | 1 + devices/levoit-core400s/common.yaml | 4 ++ .../levoit-core400s-builder-c3.yaml | 4 ++ .../levoit-core400s-builder-s3.yaml | 4 ++ .../levoit-core400s-builder.yaml | 4 ++ devices/levoit-core600s/common.yaml | 4 ++ .../levoit-core600s-builder-c3.yaml | 4 ++ .../levoit-core600s-builder-s3.yaml | 4 ++ .../levoit-core600s-builder-solo-1c.yaml | 4 ++ .../levoit-core600s-builder.yaml | 4 ++ devices/levoit-everest-air/common.yaml | 4 ++ devices/levoit-sprout/common.yaml | 4 ++ .../levoit-sprout/levoit-sprout-builder.yaml | 4 ++ devices/levoit-vital100s/common.yaml | 4 ++ .../levoit-vital100s-builder-c3.yaml | 4 ++ .../levoit-vital100s-builder-s3.yaml | 4 ++ .../levoit-vital100s-builder.yaml | 4 ++ devices/levoit-vital200s/common.yaml | 4 ++ .../levoit-vital200s-builder-c3.yaml | 4 ++ .../levoit-vital200s-builder-s3.yaml | 4 ++ .../levoit-vital200s-builder.yaml | 4 ++ 35 files changed, 196 insertions(+) diff --git a/README.md b/README.md index f9b210d..6179477 100644 --- a/README.md +++ b/README.md @@ -161,6 +161,8 @@ Available speed levels and presets are based on model. | Sprout | 1–4 | Auto, Manual | | EverestAir | 1–3 | Auto, Turbo, Manual | +The `fan_operating_mode` select exposes the active fan mode as a normal ESPHome select for dashboards that do not render fan presets directly. It stays synchronized with MCU fan-mode status and uses the same Manual / Sleep / Auto / Pet / Turbo model-specific modes as the fan preset path. + #### Vent Angle & Cover (EverestAir) diff --git a/components/levoit/fan/levoit_fan.cpp b/components/levoit/fan/levoit_fan.cpp index d15babd..b41b948 100644 --- a/components/levoit/fan/levoit_fan.cpp +++ b/components/levoit/fan/levoit_fan.cpp @@ -175,6 +175,10 @@ namespace esphome } const char *preset = device_mode_to_preset(mode); + if (mode != -1 && this->parent_ != nullptr) + { + this->parent_->publish_select(SelectType::FAN_OPERATING_MODE_SELECT, mode); + } if (preset != nullptr) { ESP_LOGD(TAG, "Device mode %d maps to preset '%s'", mode, preset); diff --git a/components/levoit/levoit.cpp b/components/levoit/levoit.cpp index 5751c3a..2a55be0 100644 --- a/components/levoit/levoit.cpp +++ b/components/levoit/levoit.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include "freertos/task.h" #include "decoder.h" #include "tlv.h" @@ -48,6 +49,25 @@ namespace esphome static const char *const TAG = "levoit"; + static const char *fan_operating_mode_to_option_(uint32_t mode) + { + switch (mode) + { + case 0: + return "Manual"; + case 1: + return "Sleep"; + case 2: + return "Auto"; + case 4: + return "Turbo"; + case 5: + return "Pet"; + default: + return nullptr; + } + } + // ===== Component ===== void Levoit::register_switch(SwitchType type, LevoitSwitch *sw) @@ -145,6 +165,24 @@ namespace esphome if (!sl) return; const auto &options = sl->traits.get_options(); + if (type == SelectType::FAN_OPERATING_MODE_SELECT) + { + const char *opt = fan_operating_mode_to_option_(value); + if (opt == nullptr) + { + ESP_LOGW(TAG, "publish_select: invalid fan mode %u", value); + return; + } + if (std::find(options.begin(), options.end(), opt) == options.end()) + { + ESP_LOGW(TAG, "publish_select: unsupported fan mode '%s' for this model", opt); + return; + } + if (sl->has_state() && sl->current_option() == opt) + return; + sl->publish_state(opt); + return; + } if (value >= options.size()) { ESP_LOGW(TAG, "publish_select: invalid index %u for type %d (options=%u)", @@ -388,6 +426,10 @@ namespace esphome switch (type) { + case SelectType::FAN_OPERATING_MODE_SELECT: + this->on_fan_command(-1, -1, value); + break; + case SelectType::AUTO_MODE: if (this->model_ == ModelType::EVERESTAIR) { diff --git a/components/levoit/select/__init__.py b/components/levoit/select/__init__.py index 598378b..6492275 100644 --- a/components/levoit/select/__init__.py +++ b/components/levoit/select/__init__.py @@ -25,6 +25,7 @@ "light_mode": SelectType.LIGHT_MODE, "white_noise_sound": SelectType.WHITE_NOISE_SOUND, "sleep_preference": SelectType.SLEEP_PREFERENCE, + "fan_operating_mode": SelectType.FAN_OPERATING_MODE_SELECT, } CONFIG_SCHEMA = select.select_schema(LevoitSelect).extend( diff --git a/components/levoit/select/levoit_select.cpp b/components/levoit/select/levoit_select.cpp index 2a31aaf..081f26f 100644 --- a/components/levoit/select/levoit_select.cpp +++ b/components/levoit/select/levoit_select.cpp @@ -11,6 +11,16 @@ namespace esphome static const char *const TAG = "levoit.select"; + static int fan_operating_mode_to_raw(const std::string &value) + { + if (value == "Manual") return 0; + if (value == "Sleep") return 1; + if (value == "Auto") return 2; + if (value == "Turbo") return 4; + if (value == "Pet") return 5; + return -1; + } + void LevoitSelect::setup() { switch (this->type_) { case SelectType::AUTO_MODE: @@ -67,6 +77,20 @@ namespace esphome // WN / DT bulk write") for the full protocol. this->traits.set_options({"Default", "Custom1", "Custom2"}); break; + case SelectType::FAN_OPERATING_MODE_SELECT: + if (parent_ && parent_->get_model() == ModelType::CORE200S) + this->traits.set_options({"Manual", "Sleep"}); + else if (parent_ && (parent_->get_model() == ModelType::CORE300S || parent_->get_model() == ModelType::CORE400S || parent_->get_model() == ModelType::CORE600S)) + this->traits.set_options({"Manual", "Sleep", "Auto"}); + else if (parent_ && (parent_->get_model() == ModelType::VITAL100S || parent_->get_model() == ModelType::VITAL200S)) + this->traits.set_options({"Manual", "Sleep", "Auto", "Pet"}); + else if (parent_ && parent_->get_model() == ModelType::SPROUT) + this->traits.set_options({"Manual", "Auto"}); + else if (parent_ && parent_->get_model() == ModelType::EVERESTAIR) + this->traits.set_options({"Manual", "Sleep", "Auto", "Turbo"}); + else + this->traits.set_options({"Manual"}); + break; default: break; } @@ -85,6 +109,14 @@ namespace esphome } uint32_t index = it - options.begin(); + if (this->type_ == SelectType::FAN_OPERATING_MODE_SELECT) { + int mode = fan_operating_mode_to_raw(value); + if (mode < 0) { + ESP_LOGW(TAG, "Unknown fan operating mode option: %s", value.c_str()); + return; + } + index = static_cast(mode); + } // Optimistic update for HA UI (string!) this->publish_state(value); diff --git a/components/levoit/types.h b/components/levoit/types.h index 14795f0..38aecff 100644 --- a/components/levoit/types.h +++ b/components/levoit/types.h @@ -150,6 +150,7 @@ namespace esphome LIGHT_MODE = 7, // Sprout: Off / Nightlight / Breathing WHITE_NOISE_SOUND = 8, // Sprout: white noise sound index (0-14, 15 sounds) SLEEP_PREFERENCE = 9, // Vital: sleep mode preference type (TLV 0x18) + FAN_OPERATING_MODE_SELECT = 10, // Active fan mode: Manual/Sleep/Auto/Pet/Turbo where supported }; static constexpr SelectType AUTO_MODE = SelectType::AUTO_MODE; static constexpr SelectType SLEEP_MODE = SelectType::SLEEP_MODE; @@ -162,6 +163,7 @@ namespace esphome static constexpr SelectType LIGHT_MODE = SelectType::LIGHT_MODE; static constexpr SelectType WHITE_NOISE_SOUND = SelectType::WHITE_NOISE_SOUND; static constexpr SelectType SLEEP_PREFERENCE = SelectType::SLEEP_PREFERENCE; + static constexpr SelectType FAN_OPERATING_MODE_SELECT = SelectType::FAN_OPERATING_MODE_SELECT; diff --git a/devices/levoit-core200s/common.yaml b/devices/levoit-core200s/common.yaml index e0b94fd..6ad430b 100644 --- a/devices/levoit-core200s/common.yaml +++ b/devices/levoit-core200s/common.yaml @@ -102,6 +102,10 @@ binary_sensor: name: "Filter Low" type: filter_low select: + - platform: levoit + levoit: levoitcore200 + name: "Fan Operating Mode" + type: fan_operating_mode - platform: levoit levoit: levoitcore200 name: "Night Light" diff --git a/devices/levoit-core200s/levoit-core200s-builder-c3.yaml b/devices/levoit-core200s/levoit-core200s-builder-c3.yaml index bf52f7b..3c7ffdb 100644 --- a/devices/levoit-core200s/levoit-core200s-builder-c3.yaml +++ b/devices/levoit-core200s/levoit-core200s-builder-c3.yaml @@ -126,6 +126,10 @@ binary_sensor: name: "Filter Low" type: filter_low select: + - platform: levoit + levoit: levoitcore200 + name: "Fan Operating Mode" + type: fan_operating_mode - platform: levoit levoit: levoitcore200 name: "Night Light" diff --git a/devices/levoit-core200s/levoit-core200s-builder-s3.yaml b/devices/levoit-core200s/levoit-core200s-builder-s3.yaml index 18463c9..3229c41 100644 --- a/devices/levoit-core200s/levoit-core200s-builder-s3.yaml +++ b/devices/levoit-core200s/levoit-core200s-builder-s3.yaml @@ -126,6 +126,10 @@ binary_sensor: name: "Filter Low" type: filter_low select: + - platform: levoit + levoit: levoitcore200 + name: "Fan Operating Mode" + type: fan_operating_mode - platform: levoit levoit: levoitcore200 name: "Night Light" diff --git a/devices/levoit-core200s/levoit-core200s-builder.yaml b/devices/levoit-core200s/levoit-core200s-builder.yaml index ff04d8c..8cf5f8a 100644 --- a/devices/levoit-core200s/levoit-core200s-builder.yaml +++ b/devices/levoit-core200s/levoit-core200s-builder.yaml @@ -123,6 +123,10 @@ binary_sensor: name: "Filter Low" type: filter_low select: + - platform: levoit + levoit: levoitcore200 + name: "Fan Operating Mode" + type: fan_operating_mode - platform: levoit levoit: levoitcore200 name: "Night Light" diff --git a/devices/levoit-core300s/common.yaml b/devices/levoit-core300s/common.yaml index b5462c9..16ef847 100644 --- a/devices/levoit-core300s/common.yaml +++ b/devices/levoit-core300s/common.yaml @@ -105,6 +105,10 @@ sensor: name: "CPU Frequency" select: + - platform: levoit + levoit: levoitcore300 + name: "Fan Operating Mode" + type: fan_operating_mode - platform: levoit levoit: levoitcore300 name: "Auto Mode" diff --git a/devices/levoit-core300s/levoit-core300s-builder-c3.yaml b/devices/levoit-core300s/levoit-core300s-builder-c3.yaml index 6c36be0..01a4b24 100644 --- a/devices/levoit-core300s/levoit-core300s-builder-c3.yaml +++ b/devices/levoit-core300s/levoit-core300s-builder-c3.yaml @@ -129,6 +129,10 @@ sensor: name: "CPU Frequency" select: + - platform: levoit + levoit: levoitcore300 + name: "Fan Operating Mode" + type: fan_operating_mode - platform: levoit levoit: levoitcore300 name: "Auto Mode" diff --git a/devices/levoit-core300s/levoit-core300s-builder-s3.yaml b/devices/levoit-core300s/levoit-core300s-builder-s3.yaml index 20f0251..77267f5 100644 --- a/devices/levoit-core300s/levoit-core300s-builder-s3.yaml +++ b/devices/levoit-core300s/levoit-core300s-builder-s3.yaml @@ -129,6 +129,10 @@ sensor: name: "CPU Frequency" select: + - platform: levoit + levoit: levoitcore300 + name: "Fan Operating Mode" + type: fan_operating_mode - platform: levoit levoit: levoitcore300 name: "Auto Mode" diff --git a/devices/levoit-core300s/levoit-core300s-builder.yaml b/devices/levoit-core300s/levoit-core300s-builder.yaml index 071a6d0..df789db 100644 --- a/devices/levoit-core300s/levoit-core300s-builder.yaml +++ b/devices/levoit-core300s/levoit-core300s-builder.yaml @@ -126,6 +126,10 @@ sensor: name: "CPU Frequency" select: + - platform: levoit + levoit: levoitcore300 + name: "Fan Operating Mode" + type: fan_operating_mode - platform: levoit levoit: levoitcore300 name: "Auto Mode" diff --git a/devices/levoit-core400s/README.md b/devices/levoit-core400s/README.md index c359ae7..ab26b26 100644 --- a/devices/levoit-core400s/README.md +++ b/devices/levoit-core400s/README.md @@ -24,6 +24,7 @@ Started from community projects ([acvigue](https://github.com/acvigue/esphome-le | Feature | Type | Notes | |---------|------|-------| | Fan | fan | 4 speeds, presets: Manual / Auto / Sleep | +| Fan Operating Mode | select | Manual / Sleep / Auto | | Auto Mode | select | Default / Quiet / Room Size | | Auto Mode Room Size | number | 9–38 m² | | Display | switch | Toggle LED display | diff --git a/devices/levoit-core400s/common.yaml b/devices/levoit-core400s/common.yaml index c57cabb..dd90e92 100644 --- a/devices/levoit-core400s/common.yaml +++ b/devices/levoit-core400s/common.yaml @@ -86,6 +86,10 @@ sensor: type: filter_life_left select: + - platform: levoit + levoit: levoitcore400 + name: "Fan Operating Mode" + type: fan_operating_mode - platform: levoit levoit: levoitcore400 name: "Auto Mode" diff --git a/devices/levoit-core400s/levoit-core400s-builder-c3.yaml b/devices/levoit-core400s/levoit-core400s-builder-c3.yaml index 1686615..a482494 100644 --- a/devices/levoit-core400s/levoit-core400s-builder-c3.yaml +++ b/devices/levoit-core400s/levoit-core400s-builder-c3.yaml @@ -110,6 +110,10 @@ sensor: type: filter_life_left select: + - platform: levoit + levoit: levoitcore400 + name: "Fan Operating Mode" + type: fan_operating_mode - platform: levoit levoit: levoitcore400 name: "Auto Mode" diff --git a/devices/levoit-core400s/levoit-core400s-builder-s3.yaml b/devices/levoit-core400s/levoit-core400s-builder-s3.yaml index 68a837b..892c2d2 100644 --- a/devices/levoit-core400s/levoit-core400s-builder-s3.yaml +++ b/devices/levoit-core400s/levoit-core400s-builder-s3.yaml @@ -110,6 +110,10 @@ sensor: type: filter_life_left select: + - platform: levoit + levoit: levoitcore400 + name: "Fan Operating Mode" + type: fan_operating_mode - platform: levoit levoit: levoitcore400 name: "Auto Mode" diff --git a/devices/levoit-core400s/levoit-core400s-builder.yaml b/devices/levoit-core400s/levoit-core400s-builder.yaml index c0a1fc2..062170d 100644 --- a/devices/levoit-core400s/levoit-core400s-builder.yaml +++ b/devices/levoit-core400s/levoit-core400s-builder.yaml @@ -107,6 +107,10 @@ sensor: type: filter_life_left select: + - platform: levoit + levoit: levoitcore400 + name: "Fan Operating Mode" + type: fan_operating_mode - platform: levoit levoit: levoitcore400 name: "Auto Mode" diff --git a/devices/levoit-core600s/common.yaml b/devices/levoit-core600s/common.yaml index 991451b..c961402 100644 --- a/devices/levoit-core600s/common.yaml +++ b/devices/levoit-core600s/common.yaml @@ -88,6 +88,10 @@ sensor: type: filter_life_left select: + - platform: levoit + levoit: levoitcore600 + name: "Fan Operating Mode" + type: fan_operating_mode - platform: levoit levoit: levoitcore600 name: "Auto Mode" diff --git a/devices/levoit-core600s/levoit-core600s-builder-c3.yaml b/devices/levoit-core600s/levoit-core600s-builder-c3.yaml index b9e2cd7..6d42975 100644 --- a/devices/levoit-core600s/levoit-core600s-builder-c3.yaml +++ b/devices/levoit-core600s/levoit-core600s-builder-c3.yaml @@ -112,6 +112,10 @@ sensor: type: filter_life_left select: + - platform: levoit + levoit: levoitcore600 + name: "Fan Operating Mode" + type: fan_operating_mode - platform: levoit levoit: levoitcore600 name: "Auto Mode" diff --git a/devices/levoit-core600s/levoit-core600s-builder-s3.yaml b/devices/levoit-core600s/levoit-core600s-builder-s3.yaml index 091ee3c..abec084 100644 --- a/devices/levoit-core600s/levoit-core600s-builder-s3.yaml +++ b/devices/levoit-core600s/levoit-core600s-builder-s3.yaml @@ -112,6 +112,10 @@ sensor: type: filter_life_left select: + - platform: levoit + levoit: levoitcore600 + name: "Fan Operating Mode" + type: fan_operating_mode - platform: levoit levoit: levoitcore600 name: "Auto Mode" diff --git a/devices/levoit-core600s/levoit-core600s-builder-solo-1c.yaml b/devices/levoit-core600s/levoit-core600s-builder-solo-1c.yaml index 13cc6f7..861d9de 100644 --- a/devices/levoit-core600s/levoit-core600s-builder-solo-1c.yaml +++ b/devices/levoit-core600s/levoit-core600s-builder-solo-1c.yaml @@ -108,6 +108,10 @@ sensor: type: filter_life_left select: + - platform: levoit + levoit: levoitcore600 + name: "Fan Operating Mode" + type: fan_operating_mode - platform: levoit levoit: levoitcore600 name: "Auto Mode" diff --git a/devices/levoit-core600s/levoit-core600s-builder.yaml b/devices/levoit-core600s/levoit-core600s-builder.yaml index ca69415..7ea37e4 100644 --- a/devices/levoit-core600s/levoit-core600s-builder.yaml +++ b/devices/levoit-core600s/levoit-core600s-builder.yaml @@ -111,6 +111,10 @@ sensor: type: filter_life_left select: + - platform: levoit + levoit: levoitcore600 + name: "Fan Operating Mode" + type: fan_operating_mode - platform: levoit levoit: levoitcore600 name: "Auto Mode" diff --git a/devices/levoit-everest-air/common.yaml b/devices/levoit-everest-air/common.yaml index dfcbab5..d4e723a 100644 --- a/devices/levoit-everest-air/common.yaml +++ b/devices/levoit-everest-air/common.yaml @@ -97,6 +97,10 @@ sensor: type: filter_life_left select: + - platform: levoit + levoit: leveverestair + name: "Fan Operating Mode" + type: fan_operating_mode - platform: levoit levoit: leveverestair name: "Auto Mode" diff --git a/devices/levoit-sprout/common.yaml b/devices/levoit-sprout/common.yaml index a36f720..92ceb34 100644 --- a/devices/levoit-sprout/common.yaml +++ b/devices/levoit-sprout/common.yaml @@ -125,6 +125,10 @@ light: default_transition_length: 0s select: + - platform: levoit + levoit: levoitsprout + name: "Fan Operating Mode" + type: fan_operating_mode - platform: levoit levoit: levoitsprout name: "Auto Mode" diff --git a/devices/levoit-sprout/levoit-sprout-builder.yaml b/devices/levoit-sprout/levoit-sprout-builder.yaml index ba23e87..88cb5e3 100644 --- a/devices/levoit-sprout/levoit-sprout-builder.yaml +++ b/devices/levoit-sprout/levoit-sprout-builder.yaml @@ -146,6 +146,10 @@ light: default_transition_length: 0s select: + - platform: levoit + levoit: levoitsprout + name: "Fan Operating Mode" + type: fan_operating_mode - platform: levoit levoit: levoitsprout name: "Auto Mode" diff --git a/devices/levoit-vital100s/common.yaml b/devices/levoit-vital100s/common.yaml index 6240ebf..2c44bf3 100644 --- a/devices/levoit-vital100s/common.yaml +++ b/devices/levoit-vital100s/common.yaml @@ -88,6 +88,10 @@ sensor: type: filter_life_left select: + - platform: levoit + levoit: levoitvital100 + name: "Fan Operating Mode" + type: fan_operating_mode - platform: levoit levoit: levoitvital100 name: "Auto Mode" diff --git a/devices/levoit-vital100s/levoit-vital100s-builder-c3.yaml b/devices/levoit-vital100s/levoit-vital100s-builder-c3.yaml index cf6d2e8..d84c253 100644 --- a/devices/levoit-vital100s/levoit-vital100s-builder-c3.yaml +++ b/devices/levoit-vital100s/levoit-vital100s-builder-c3.yaml @@ -112,6 +112,10 @@ sensor: type: filter_life_left select: + - platform: levoit + levoit: levoitvital100 + name: "Fan Operating Mode" + type: fan_operating_mode - platform: levoit levoit: levoitvital100 name: "Auto Mode" diff --git a/devices/levoit-vital100s/levoit-vital100s-builder-s3.yaml b/devices/levoit-vital100s/levoit-vital100s-builder-s3.yaml index 2034e01..dbe3716 100644 --- a/devices/levoit-vital100s/levoit-vital100s-builder-s3.yaml +++ b/devices/levoit-vital100s/levoit-vital100s-builder-s3.yaml @@ -112,6 +112,10 @@ sensor: type: filter_life_left select: + - platform: levoit + levoit: levoitvital100 + name: "Fan Operating Mode" + type: fan_operating_mode - platform: levoit levoit: levoitvital100 name: "Auto Mode" diff --git a/devices/levoit-vital100s/levoit-vital100s-builder.yaml b/devices/levoit-vital100s/levoit-vital100s-builder.yaml index 86d5922..c20e475 100644 --- a/devices/levoit-vital100s/levoit-vital100s-builder.yaml +++ b/devices/levoit-vital100s/levoit-vital100s-builder.yaml @@ -115,6 +115,10 @@ sensor: type: filter_life_left select: + - platform: levoit + levoit: levoitvital100 + name: "Fan Operating Mode" + type: fan_operating_mode - platform: levoit levoit: levoitvital100 name: "Auto Mode" diff --git a/devices/levoit-vital200s/common.yaml b/devices/levoit-vital200s/common.yaml index 0c0bf9c..a567f79 100644 --- a/devices/levoit-vital200s/common.yaml +++ b/devices/levoit-vital200s/common.yaml @@ -116,6 +116,10 @@ sensor: type: filter_life_left select: + - platform: levoit + levoit: levoitvital200 + name: "Fan Operating Mode" + type: fan_operating_mode - platform: levoit levoit: levoitvital200 name: "Auto Mode" diff --git a/devices/levoit-vital200s/levoit-vital200s-builder-c3.yaml b/devices/levoit-vital200s/levoit-vital200s-builder-c3.yaml index 779d727..85b9f6d 100644 --- a/devices/levoit-vital200s/levoit-vital200s-builder-c3.yaml +++ b/devices/levoit-vital200s/levoit-vital200s-builder-c3.yaml @@ -140,6 +140,10 @@ sensor: type: filter_life_left select: + - platform: levoit + levoit: levoitvital200 + name: "Fan Operating Mode" + type: fan_operating_mode - platform: levoit levoit: levoitvital200 name: "Auto Mode" diff --git a/devices/levoit-vital200s/levoit-vital200s-builder-s3.yaml b/devices/levoit-vital200s/levoit-vital200s-builder-s3.yaml index 0239376..3661e40 100644 --- a/devices/levoit-vital200s/levoit-vital200s-builder-s3.yaml +++ b/devices/levoit-vital200s/levoit-vital200s-builder-s3.yaml @@ -140,6 +140,10 @@ sensor: type: filter_life_left select: + - platform: levoit + levoit: levoitvital200 + name: "Fan Operating Mode" + type: fan_operating_mode - platform: levoit levoit: levoitvital200 name: "Auto Mode" diff --git a/devices/levoit-vital200s/levoit-vital200s-builder.yaml b/devices/levoit-vital200s/levoit-vital200s-builder.yaml index 2835e8c..be01f47 100644 --- a/devices/levoit-vital200s/levoit-vital200s-builder.yaml +++ b/devices/levoit-vital200s/levoit-vital200s-builder.yaml @@ -135,6 +135,10 @@ sensor: type: filter_life_left select: + - platform: levoit + levoit: levoitvital200 + name: "Fan Operating Mode" + type: fan_operating_mode - platform: levoit levoit: levoitvital200 name: "Auto Mode" From c66629574f0868da3dcc4afd331e87d36e8ec427 Mon Sep 17 00:00:00 2001 From: edennelson Date: Tue, 30 Jun 2026 14:32:04 -0700 Subject: [PATCH 2/2] Sync fan mode select from fan control --- components/levoit/fan/levoit_fan.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/levoit/fan/levoit_fan.cpp b/components/levoit/fan/levoit_fan.cpp index b41b948..aaa5276 100644 --- a/components/levoit/fan/levoit_fan.cpp +++ b/components/levoit/fan/levoit_fan.cpp @@ -139,6 +139,10 @@ namespace esphome } // Only sends fields != -1 (as long as your parent respects sentinels) + if (mode_cmd != -1) + { + parent_->publish_select(SelectType::FAN_OPERATING_MODE_SELECT, mode_cmd); + } parent_->on_fan_command(power_cmd, speed_cmd, mode_cmd); this->publish_state();