mirror of https://github.com/esphome/esphome.git
230 lines
8.4 KiB
C++
230 lines
8.4 KiB
C++
#include "humidifier.h"
|
|
#include "esphome/core/macros.h"
|
|
|
|
namespace esphome {
|
|
namespace humidifier {
|
|
|
|
static const char *const TAG = "humidifier";
|
|
|
|
void HumidifierCall::perform() {
|
|
this->parent_->control_callback_.call(*this);
|
|
ESP_LOGD(TAG, "'%s' - Setting", this->parent_->get_name().c_str());
|
|
this->validate_();
|
|
if (this->mode_.has_value()) {
|
|
const LogString *mode_s = humidifier_mode_to_string(*this->mode_);
|
|
ESP_LOGD(TAG, " Mode: %s", LOG_STR_ARG(mode_s));
|
|
}
|
|
if (this->target_humidity_.has_value()) {
|
|
ESP_LOGD(TAG, " Target Humidity: %.0f", *this->target_humidity_);
|
|
}
|
|
this->parent_->control(*this);
|
|
}
|
|
void HumidifierCall::validate_() {
|
|
auto traits = this->parent_->get_traits();
|
|
if (this->mode_.has_value()) {
|
|
auto mode = *this->mode_;
|
|
if (!traits.supports_mode(mode)) {
|
|
ESP_LOGW(TAG, " Mode %s is not supported by this device!", LOG_STR_ARG(humidifier_mode_to_string(mode)));
|
|
this->mode_.reset();
|
|
}
|
|
}
|
|
if (this->target_humidity_.has_value()) {
|
|
auto target = *this->target_humidity_;
|
|
// if (traits.get_supports_target_humidity()) {
|
|
if (std::isnan(target)) {
|
|
ESP_LOGW(TAG, " Target humidity must not be NAN!");
|
|
this->target_humidity_.reset();
|
|
}
|
|
}
|
|
}
|
|
HumidifierCall &HumidifierCall::set_mode(HumidifierMode mode) {
|
|
this->mode_ = mode;
|
|
return *this;
|
|
}
|
|
HumidifierCall &HumidifierCall::set_mode(const std::string &mode) {
|
|
if (str_equals_case_insensitive(mode, "OFF")) {
|
|
this->set_mode(HUMIDIFIER_MODE_OFF);
|
|
} else if (str_equals_case_insensitive(mode, "NORMAL")) {
|
|
this->set_mode(HUMIDIFIER_MODE_NORMAL);
|
|
} else if (str_equals_case_insensitive(mode, "ECO")) {
|
|
this->set_mode(HUMIDIFIER_MODE_ECO);
|
|
} else if (str_equals_case_insensitive(mode, "AWAY")) {
|
|
this->set_mode(HUMIDIFIER_MODE_AWAY);
|
|
} else if (str_equals_case_insensitive(mode, "BOOST")) {
|
|
this->set_mode(HUMIDIFIER_MODE_BOOST);
|
|
} else if (str_equals_case_insensitive(mode, "COMFORT")) {
|
|
this->set_mode(HUMIDIFIER_MODE_COMFORT);
|
|
} else if (str_equals_case_insensitive(mode, "HOME")) {
|
|
this->set_mode(HUMIDIFIER_MODE_HOME);
|
|
} else if (str_equals_case_insensitive(mode, "SLEEP")) {
|
|
this->set_mode(HUMIDIFIER_MODE_SLEEP);
|
|
} else if (str_equals_case_insensitive(mode, "AUTO")) {
|
|
this->set_mode(HUMIDIFIER_MODE_AUTO);
|
|
} else if (str_equals_case_insensitive(mode, "BABY")) {
|
|
this->set_mode(HUMIDIFIER_MODE_BABY);
|
|
} else {
|
|
ESP_LOGW(TAG, "'%s' - Unrecognized mode %s", this->parent_->get_name().c_str(), mode.c_str());
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
HumidifierCall &HumidifierCall::set_target_humidity(float target_humidity) {
|
|
this->target_humidity_ = target_humidity;
|
|
return *this;
|
|
}
|
|
|
|
const optional<HumidifierMode> &HumidifierCall::get_mode() const { return this->mode_; }
|
|
const optional<float> &HumidifierCall::get_target_humidity() const { return this->target_humidity_; }
|
|
|
|
HumidifierCall &HumidifierCall::set_target_humidity(optional<float> target_humidity) {
|
|
this->target_humidity_ = target_humidity;
|
|
return *this;
|
|
}
|
|
HumidifierCall &HumidifierCall::set_mode(optional<HumidifierMode> mode) {
|
|
this->mode_ = mode;
|
|
return *this;
|
|
}
|
|
|
|
void Humidifier::add_on_state_callback(std::function<void(Humidifier &)> &&callback) {
|
|
this->state_callback_.add(std::move(callback));
|
|
}
|
|
|
|
void Humidifier::add_on_control_callback(std::function<void(HumidifierCall &)> &&callback) {
|
|
this->control_callback_.add(std::move(callback));
|
|
}
|
|
|
|
// Random 32bit value; If this changes existing restore preferences are invalidated
|
|
static const uint32_t RESTORE_STATE_VERSION = 0x848EA6ADUL;
|
|
|
|
optional<HumidifierDeviceRestoreState> Humidifier::restore_state_() {
|
|
this->rtc_ = global_preferences->make_preference<HumidifierDeviceRestoreState>(this->get_object_id_hash() ^
|
|
RESTORE_STATE_VERSION);
|
|
HumidifierDeviceRestoreState recovered{};
|
|
if (!this->rtc_.load(&recovered))
|
|
return {};
|
|
return recovered;
|
|
}
|
|
void Humidifier::save_state_() {
|
|
#if (defined(USE_ESP_IDF) || (defined(USE_ESP8266) && USE_ARDUINO_VERSION_CODE >= VERSION_CODE(3, 0, 0))) && \
|
|
!defined(CLANG_TIDY)
|
|
#pragma GCC diagnostic ignored "-Wclass-memaccess"
|
|
#define TEMP_IGNORE_MEMACCESS
|
|
#endif
|
|
HumidifierDeviceRestoreState state{};
|
|
// initialize as zero to prevent random data on stack triggering erase
|
|
memset(&state, 0, sizeof(HumidifierDeviceRestoreState));
|
|
#ifdef TEMP_IGNORE_MEMACCESS
|
|
#pragma GCC diagnostic pop
|
|
#undef TEMP_IGNORE_MEMACCESS
|
|
#endif
|
|
state.mode = this->mode;
|
|
auto traits = this->get_traits();
|
|
if (traits.get_supports_target_humidity()) {
|
|
state.target_humidity = this->target_humidity;
|
|
}
|
|
|
|
this->rtc_.save(&state);
|
|
}
|
|
|
|
void Humidifier::publish_state() {
|
|
ESP_LOGD(TAG, "'%s' - Sending state:", this->name_.c_str());
|
|
auto traits = this->get_traits();
|
|
|
|
ESP_LOGD(TAG, " Mode: %s", LOG_STR_ARG(humidifier_mode_to_string(this->mode)));
|
|
if (traits.get_supports_action()) {
|
|
ESP_LOGD(TAG, " Action: %s", LOG_STR_ARG(humidifier_action_to_string(this->action)));
|
|
}
|
|
if (traits.get_supports_current_humidity()) {
|
|
ESP_LOGD(TAG, " Current Humidity: %.0f%%", this->current_humidity);
|
|
}
|
|
if (traits.get_supports_target_humidity()) {
|
|
ESP_LOGD(TAG, " Target Humidity: %.0f%%", this->target_humidity);
|
|
}
|
|
// Send state to frontend
|
|
this->state_callback_.call(*this);
|
|
// Save state
|
|
this->save_state_();
|
|
}
|
|
HumidifierTraits Humidifier::get_traits() {
|
|
auto traits = this->traits();
|
|
if (this->visual_min_humidity_override_.has_value()) {
|
|
traits.set_visual_min_humidity(*this->visual_min_humidity_override_);
|
|
}
|
|
if (this->visual_max_humidity_override_.has_value()) {
|
|
traits.set_visual_max_humidity(*this->visual_max_humidity_override_);
|
|
}
|
|
if (this->visual_target_humidity_step_override_.has_value()) {
|
|
traits.set_visual_target_humidity_step(*this->visual_target_humidity_step_override_);
|
|
traits.set_visual_current_humidity_step(*this->visual_current_humidity_step_override_);
|
|
}
|
|
|
|
return traits;
|
|
}
|
|
|
|
void Humidifier::set_visual_min_humidity_override(float visual_min_humidity_override) {
|
|
this->visual_min_humidity_override_ = visual_min_humidity_override;
|
|
}
|
|
void Humidifier::set_visual_max_humidity_override(float visual_max_humidity_override) {
|
|
this->visual_max_humidity_override_ = visual_max_humidity_override;
|
|
}
|
|
void Humidifier::set_visual_humidity_step_override(float target, float current) {
|
|
this->visual_target_humidity_step_override_ = target;
|
|
this->visual_current_humidity_step_override_ = current;
|
|
}
|
|
|
|
HumidifierCall Humidifier::make_call() { return HumidifierCall(this); }
|
|
|
|
HumidifierCall HumidifierDeviceRestoreState::to_call(Humidifier *humidifier) {
|
|
auto call = humidifier->make_call();
|
|
auto traits = humidifier->get_traits();
|
|
call.set_mode(this->mode);
|
|
if (traits.get_supports_target_humidity()) {
|
|
call.set_target_humidity(this->target_humidity);
|
|
}
|
|
return call;
|
|
}
|
|
|
|
void HumidifierDeviceRestoreState::apply(Humidifier *humidifier) {
|
|
auto traits = humidifier->get_traits();
|
|
humidifier->mode = this->mode;
|
|
if (traits.get_supports_target_humidity()) {
|
|
humidifier->target_humidity = this->target_humidity;
|
|
}
|
|
humidifier->publish_state();
|
|
}
|
|
|
|
template<typename T1, typename T2> bool set_alternative(optional<T1> &dst, optional<T2> &alt, const T1 &src) {
|
|
bool is_changed = alt.has_value();
|
|
alt.reset();
|
|
if (is_changed || dst != src) {
|
|
dst = src;
|
|
is_changed = true;
|
|
}
|
|
return is_changed;
|
|
}
|
|
|
|
void Humidifier::dump_traits_(const char *tag) {
|
|
auto traits = this->get_traits();
|
|
ESP_LOGCONFIG(tag, "HumidifierTraits:");
|
|
ESP_LOGCONFIG(tag, " [x] Visual settings:");
|
|
ESP_LOGCONFIG(tag, " - Min humidity: %.1f", traits.get_visual_min_humidity());
|
|
ESP_LOGCONFIG(tag, " - Max humidity: %.1f", traits.get_visual_max_humidity());
|
|
ESP_LOGCONFIG(tag, " - Humidity step:");
|
|
ESP_LOGCONFIG(tag, " Target: %.0f%%", traits.get_visual_target_humidity_step());
|
|
ESP_LOGCONFIG(tag, " Current: %.1F%%", traits.get_visual_current_humidity_step());
|
|
if (traits.get_supports_current_humidity()) {
|
|
ESP_LOGCONFIG(tag, " [x] Supports current humidity");
|
|
}
|
|
if (traits.get_supports_action()) {
|
|
ESP_LOGCONFIG(tag, " [x] Supports action");
|
|
}
|
|
if (!traits.get_supported_modes().empty()) {
|
|
ESP_LOGCONFIG(tag, " [x] Supported modes:");
|
|
for (HumidifierMode m : traits.get_supported_modes())
|
|
ESP_LOGCONFIG(tag, " - %s", LOG_STR_ARG(humidifier_mode_to_string(m)));
|
|
}
|
|
}
|
|
|
|
} // namespace humidifier
|
|
} // namespace esphome
|