2021-11-11 18:46:56 +00:00
|
|
|
#include "pool_controller.h"
|
2021-09-10 12:42:29 +00:00
|
|
|
#include "esphome/components/time/automation.h"
|
|
|
|
#include "esphome/core/application.h"
|
|
|
|
#include "esphome/core/base_automation.h"
|
|
|
|
#include "esphome/core/log.h"
|
2024-07-22 23:34:02 +00:00
|
|
|
#include "esphome/core/time.h"
|
2021-09-10 12:42:29 +00:00
|
|
|
|
|
|
|
namespace esphome {
|
|
|
|
namespace pool_controller {
|
|
|
|
|
2024-07-22 23:34:02 +00:00
|
|
|
static const char *const TAG = "pool.controller";
|
2021-09-10 12:42:29 +00:00
|
|
|
|
|
|
|
static const uint32_t RUNTIME_30_MINUTES_PER_HALF_HOUR = UINT32_MAX;
|
|
|
|
static const uint32_t RUNTIME_15_MINUTES_PER_HALF_HOUR = 900000;
|
|
|
|
static const uint32_t RUNTIME_10_MINUTES_PER_HALF_HOUR = 600000;
|
|
|
|
|
|
|
|
// Minimum time the pump needs to be off before the automation will turn it back on (300000 = 5 minutes)
|
|
|
|
static const uint32_t MINIMUM_AUTOMATION_PUMP_OFF_TIME = 300000;
|
|
|
|
|
|
|
|
// Minimum time the pump needs to be on before the automation will turn it back off (300000 = 5 minutes)
|
|
|
|
static const uint32_t MINIMUM_AUTOMATION_PUMP_ON_TIME = 300000;
|
|
|
|
|
|
|
|
PoolController::PoolController() {
|
2024-07-22 23:34:02 +00:00
|
|
|
ESP_LOGCONFIG(TAG, "Creating pump mode select component");
|
2021-09-10 12:42:29 +00:00
|
|
|
this->pump_select_ = new PoolSelect();
|
|
|
|
App.register_component(this->pump_select_);
|
|
|
|
App.register_select(this->pump_select_);
|
|
|
|
this->pump_select_->set_name("Pool Pump Mode");
|
2024-07-22 23:34:02 +00:00
|
|
|
this->pump_select_->set_object_id("pump_select");
|
2021-11-11 18:46:56 +00:00
|
|
|
this->pump_select_->set_icon("mdi:pump");
|
2024-07-22 23:34:02 +00:00
|
|
|
this->pump_select_->set_disabled_by_default(false);
|
2021-09-10 12:42:29 +00:00
|
|
|
this->pump_select_->traits.set_options({"Off", "Normal", "Always Except Peak", "Always"});
|
2024-07-22 23:34:02 +00:00
|
|
|
this->pump_select_->set_initial_option("Off");
|
2022-06-07 02:41:13 +00:00
|
|
|
this->pump_select_->add_on_state_callback([this](const std::string &value, size_t index) {
|
2021-09-10 12:42:29 +00:00
|
|
|
this->pump_mode_ = static_cast<PumpMode>(index);
|
|
|
|
});
|
|
|
|
|
2024-07-22 23:34:02 +00:00
|
|
|
ESP_LOGCONFIG(TAG, "Creating cleaner mode select component");
|
2021-09-10 12:42:29 +00:00
|
|
|
this->cleaner_select_ = new PoolSelect();
|
|
|
|
App.register_component(this->cleaner_select_);
|
|
|
|
App.register_select(this->cleaner_select_);
|
|
|
|
this->cleaner_select_->set_name("Pool Cleaner Mode");
|
2024-07-22 23:34:02 +00:00
|
|
|
this->cleaner_select_->set_object_id("cleaner_select");
|
2021-11-11 18:46:56 +00:00
|
|
|
this->cleaner_select_->set_icon("mdi:robot-vacuum");
|
2024-07-22 23:34:02 +00:00
|
|
|
this->cleaner_select_->set_disabled_by_default(false);
|
2021-09-10 12:42:29 +00:00
|
|
|
this->cleaner_select_->traits.set_options({"Off", "Normal", "When Pump Is On"});
|
2024-07-22 23:34:02 +00:00
|
|
|
this->cleaner_select_->set_initial_option("Off");
|
2022-06-07 02:41:13 +00:00
|
|
|
this->cleaner_select_->add_on_state_callback([this](const std::string &value, size_t index) {
|
2021-09-10 12:42:29 +00:00
|
|
|
this->cleaner_mode_ = static_cast<CleanerMode>(index);
|
|
|
|
});
|
|
|
|
|
|
|
|
// this->heat_select_ = new PoolSelect();
|
|
|
|
// App.register_component(this->heat_select_);
|
|
|
|
// App.register_select(this->heat_select_);
|
|
|
|
// this->heat_select_->set_name("Pool Heat Mode");
|
|
|
|
// this->heat_select_->traits.set_icon("mdi:thermometer");
|
|
|
|
// this->heat_select_->traits.set_options({"Off", "Normal", "Always"});
|
|
|
|
}
|
|
|
|
|
|
|
|
void PoolController::set_time(time::RealTimeClock *time) {
|
|
|
|
this->time_ = time;
|
|
|
|
|
|
|
|
ESP_LOGD(TAG, "Adding cron trigger");
|
|
|
|
auto cron_trigger = new time::CronTrigger(time);
|
|
|
|
cron_trigger->add_second(0);
|
|
|
|
cron_trigger->add_minutes({0, 30});
|
|
|
|
cron_trigger->add_hours({0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23});
|
|
|
|
cron_trigger->add_days_of_month({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31});
|
|
|
|
cron_trigger->add_months({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12});
|
|
|
|
cron_trigger->add_days_of_week({1, 2, 3, 4, 5, 6, 7});
|
|
|
|
App.register_component(cron_trigger);
|
|
|
|
auto lambda_action = new LambdaAction<>([=]() -> void {
|
|
|
|
this->pump_switch_->reset_runtime();
|
|
|
|
this->cleaner_switch_->reset_runtime();
|
|
|
|
});
|
|
|
|
auto automation = new Automation<>(cron_trigger);
|
|
|
|
automation->add_actions({lambda_action});
|
|
|
|
}
|
|
|
|
|
|
|
|
void PoolController::set_pump_switch(switch_::Switch *pump_switch) {
|
|
|
|
this->pump_switch_ = new PumpSwitch(pump_switch);
|
|
|
|
App.register_switch(this->pump_switch_);
|
2024-07-22 23:34:02 +00:00
|
|
|
this->pump_switch_->set_name("Pool Pump");
|
|
|
|
this->pump_switch_->set_object_id("controller_managed_pump_switch");
|
|
|
|
this->pump_switch_->set_icon("mdi:pump");
|
2021-09-10 12:42:29 +00:00
|
|
|
this->pump_switch_->add_turn_off_check([this]() -> bool {
|
2021-09-20 20:25:11 +00:00
|
|
|
ESP_LOGD(TAG, "Pump switch turn off check is checking the state of the pool cleaner");
|
2021-09-10 12:42:29 +00:00
|
|
|
if (this->cleaner_switch_->state) {
|
|
|
|
this->cleaner_switch_->turn_off();
|
|
|
|
}
|
|
|
|
return this->cleaner_switch_->get_current_off_time() > 5000;
|
|
|
|
});
|
2024-07-22 23:34:02 +00:00
|
|
|
App.register_component(this->pump_switch_);
|
2021-09-10 12:42:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void PoolController::set_cleaner_switch(switch_::Switch *cleaner_switch) {
|
|
|
|
this->cleaner_switch_ = new PumpSwitch(cleaner_switch);
|
|
|
|
App.register_switch(this->cleaner_switch_);
|
2024-07-22 23:34:02 +00:00
|
|
|
this->cleaner_switch_->set_name("Pool Cleaner");
|
|
|
|
this->cleaner_switch_->set_object_id("controller_managed_cleaner_switch");
|
|
|
|
this->cleaner_switch_->set_icon("mdi:robot-vacuum");
|
2021-09-10 12:42:29 +00:00
|
|
|
this->cleaner_switch_->add_turn_on_check([this]() {
|
2021-09-20 20:25:11 +00:00
|
|
|
ESP_LOGD(TAG, "Cleaner switch turn on check is checking the state of the pool pump");
|
2021-09-10 12:42:29 +00:00
|
|
|
if (!this->pump_switch_->state) {
|
|
|
|
this->pump_switch_->turn_on();
|
|
|
|
}
|
|
|
|
return this->pump_switch_->get_current_on_time() > 5000;
|
|
|
|
});
|
2024-07-22 23:34:02 +00:00
|
|
|
App.register_component(this->cleaner_switch_);
|
2021-09-10 12:42:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void PoolController::setup() {
|
|
|
|
}
|
|
|
|
|
|
|
|
void PoolController::loop() {
|
|
|
|
manage_pump_();
|
|
|
|
|
|
|
|
manage_cleaner_();
|
|
|
|
}
|
|
|
|
|
|
|
|
void PoolController::manage_pump_() {
|
|
|
|
uint32_t desired_runtime = 0;
|
2024-07-22 23:34:02 +00:00
|
|
|
ESPTime now = this->time_->now();
|
2021-09-20 20:25:11 +00:00
|
|
|
uint8_t hour = now.hour;
|
|
|
|
uint8_t day_of_week = now.day_of_week;
|
2021-09-10 12:42:29 +00:00
|
|
|
switch (this->pump_mode_) {
|
|
|
|
case PumpMode::PUMP_MODE_OFF:
|
|
|
|
if (this->pump_switch_->state) {
|
|
|
|
this->pump_switch_->turn_off();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PumpMode::PUMP_MODE_NORMAL:
|
|
|
|
if (hour >= 4 && hour < 6) {
|
|
|
|
desired_runtime = RUNTIME_30_MINUTES_PER_HALF_HOUR; // normal cleaner run time
|
2021-09-20 20:25:11 +00:00
|
|
|
} else if (day_of_week > 1 && day_of_week < 7 && hour >= 15 && hour < 20 ) {
|
2021-09-10 12:42:29 +00:00
|
|
|
desired_runtime = RUNTIME_10_MINUTES_PER_HALF_HOUR; // peak electric rate
|
2024-07-22 23:34:02 +00:00
|
|
|
} else if (hour >= 6 && hour < 22) {
|
2021-09-20 20:25:11 +00:00
|
|
|
desired_runtime = RUNTIME_15_MINUTES_PER_HALF_HOUR;
|
2021-09-10 12:42:29 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PumpMode::PUMP_MODE_ALWAYS_EXCEPT_PEAK:
|
2021-09-20 20:25:11 +00:00
|
|
|
if (day_of_week == 1 || day_of_week == 7 || hour < 15 || hour >= 20) {
|
2021-09-10 12:42:29 +00:00
|
|
|
desired_runtime = RUNTIME_30_MINUTES_PER_HALF_HOUR;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PumpMode::PUMP_MODE_ALWAYS:
|
|
|
|
desired_runtime = RUNTIME_30_MINUTES_PER_HALF_HOUR;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!this->pump_switch_->state && desired_runtime > this->pump_switch_->get_runtime() && this->pump_switch_->get_current_off_time() > MINIMUM_AUTOMATION_PUMP_OFF_TIME) {
|
|
|
|
this->pump_switch_->turn_on();
|
|
|
|
} else if (this->pump_switch_->state && desired_runtime < this->pump_switch_->get_runtime() && this->pump_switch_->get_current_on_time() > MINIMUM_AUTOMATION_PUMP_ON_TIME) {
|
|
|
|
this->pump_switch_->turn_off();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PoolController::manage_cleaner_() {
|
|
|
|
bool desired_state = false;
|
2021-09-20 20:25:11 +00:00
|
|
|
uint8_t hour = this->time_->now().hour;
|
2021-09-10 12:42:29 +00:00
|
|
|
switch (this->cleaner_mode_) {
|
|
|
|
case CleanerMode::CLEANER_MODE_OFF:
|
|
|
|
if (this->cleaner_switch_->state) {
|
|
|
|
this->cleaner_switch_->turn_off();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CleanerMode::CLEANER_MODE_NORMAL:
|
|
|
|
if (hour >= 4 && hour < 6) {
|
|
|
|
desired_state = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CleanerMode::CLEANER_MODE_WHEN_PUMP_IS_ON:
|
|
|
|
if (this->pump_switch_->state) {
|
|
|
|
desired_state = true;
|
|
|
|
}
|
2021-09-20 20:25:11 +00:00
|
|
|
break;
|
2021-09-10 12:42:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!this->cleaner_switch_->state && desired_state && this->cleaner_switch_->get_current_off_time() > MINIMUM_AUTOMATION_PUMP_OFF_TIME) {
|
|
|
|
this->cleaner_switch_->turn_on();
|
|
|
|
} else if (this->cleaner_switch_->state && !desired_state && this->cleaner_switch_->get_current_on_time() > MINIMUM_AUTOMATION_PUMP_ON_TIME) {
|
|
|
|
this->cleaner_switch_->turn_off();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace pool_controller
|
|
|
|
} // namespace esphome
|