Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,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)

Expand Down
8 changes: 8 additions & 0 deletions components/levoit/fan/levoit_fan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,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();
Expand Down Expand Up @@ -179,6 +183,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);
Expand Down
42 changes: 42 additions & 0 deletions components/levoit/levoit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <time.h>
#include <vector>
#include <functional>
#include <algorithm>
#include "freertos/task.h"
#include "decoder.h"
#include "tlv.h"
Expand Down Expand Up @@ -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;
}
}

static bool supports_auto_fan_mode_(ModelType model)
{
return model != ModelType::CORE200S;
Expand Down Expand Up @@ -149,6 +169,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)",
Expand Down Expand Up @@ -394,6 +432,10 @@ namespace esphome

switch (type)
{
case SelectType::FAN_OPERATING_MODE_SELECT:
this->on_fan_command(-1, -1, value);
break;

case SelectType::AUTO_MODE:
{
bool sent_auto_profile = false;
Expand Down
1 change: 1 addition & 0 deletions components/levoit/select/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
32 changes: 32 additions & 0 deletions components/levoit/select/levoit_select.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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;
}
Expand All @@ -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<uint32_t>(mode);
}

// Optimistic update for HA UI (string!)
this->publish_state(value);
Expand Down
2 changes: 2 additions & 0 deletions components/levoit/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;



Expand Down
4 changes: 4 additions & 0 deletions devices/levoit-core200s/common.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 4 additions & 0 deletions devices/levoit-core200s/levoit-core200s-builder-c3.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 4 additions & 0 deletions devices/levoit-core200s/levoit-core200s-builder-s3.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 4 additions & 0 deletions devices/levoit-core200s/levoit-core200s-builder.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 4 additions & 0 deletions devices/levoit-core300s/common.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 4 additions & 0 deletions devices/levoit-core300s/levoit-core300s-builder-c3.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 4 additions & 0 deletions devices/levoit-core300s/levoit-core300s-builder-s3.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 4 additions & 0 deletions devices/levoit-core300s/levoit-core300s-builder.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
1 change: 1 addition & 0 deletions devices/levoit-core400s/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down
4 changes: 4 additions & 0 deletions devices/levoit-core400s/common.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 4 additions & 0 deletions devices/levoit-core400s/levoit-core400s-builder-c3.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 4 additions & 0 deletions devices/levoit-core400s/levoit-core400s-builder-s3.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 4 additions & 0 deletions devices/levoit-core400s/levoit-core400s-builder.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 4 additions & 0 deletions devices/levoit-core600s/common.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 4 additions & 0 deletions devices/levoit-core600s/levoit-core600s-builder-c3.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 4 additions & 0 deletions devices/levoit-core600s/levoit-core600s-builder-s3.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 4 additions & 0 deletions devices/levoit-core600s/levoit-core600s-builder-solo-1c.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 4 additions & 0 deletions devices/levoit-core600s/levoit-core600s-builder.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 4 additions & 0 deletions devices/levoit-everest-air/common.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 4 additions & 0 deletions devices/levoit-sprout/common.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Loading