[sprinkler] Remove internal latching valve support (#12603)

This commit is contained in:
Keith Burzinski
2025-12-22 13:13:18 -06:00
committed by GitHub
parent cd45fe0c3a
commit 08c0f65f30
3 changed files with 84 additions and 271 deletions

View File

@@ -19,6 +19,7 @@ from esphome.const import (
UNIT_MINUTE,
UNIT_SECOND,
)
from esphome.helpers import docs_url
AUTO_LOAD = ["number", "switch"]
CODEOWNERS = ["@kbx81"]
@@ -162,55 +163,9 @@ def validate_sprinkler(config):
raise cv.Invalid(
f"{CONF_RUN_DURATION} must be greater than {CONF_VALVE_OPEN_DELAY}"
)
if (
CONF_PUMP_OFF_SWITCH_ID in valve and CONF_PUMP_ON_SWITCH_ID not in valve
) or (
CONF_PUMP_ON_SWITCH_ID in valve and CONF_PUMP_OFF_SWITCH_ID not in valve
):
if CONF_VALVE_SWITCH_ID not in valve:
raise cv.Invalid(
f"Both {CONF_PUMP_OFF_SWITCH_ID} and {CONF_PUMP_ON_SWITCH_ID} must be specified for latching pump configuration"
)
if CONF_PUMP_SWITCH_ID in valve and (
CONF_PUMP_OFF_SWITCH_ID in valve or CONF_PUMP_ON_SWITCH_ID in valve
):
raise cv.Invalid(
f"Do not specify {CONF_PUMP_OFF_SWITCH_ID} or {CONF_PUMP_ON_SWITCH_ID} when using {CONF_PUMP_SWITCH_ID}"
)
if CONF_PUMP_PULSE_DURATION not in sprinkler_controller and (
CONF_PUMP_OFF_SWITCH_ID in valve or CONF_PUMP_ON_SWITCH_ID in valve
):
raise cv.Invalid(
f"{CONF_PUMP_PULSE_DURATION} must be specified when using {CONF_PUMP_OFF_SWITCH_ID} and {CONF_PUMP_ON_SWITCH_ID}"
)
if (
CONF_VALVE_OFF_SWITCH_ID in valve
and CONF_VALVE_ON_SWITCH_ID not in valve
) or (
CONF_VALVE_ON_SWITCH_ID in valve
and CONF_VALVE_OFF_SWITCH_ID not in valve
):
raise cv.Invalid(
f"Both {CONF_VALVE_OFF_SWITCH_ID} and {CONF_VALVE_ON_SWITCH_ID} must be specified for latching valve configuration"
)
if CONF_VALVE_SWITCH_ID in valve and (
CONF_VALVE_OFF_SWITCH_ID in valve or CONF_VALVE_ON_SWITCH_ID in valve
):
raise cv.Invalid(
f"Do not specify {CONF_VALVE_OFF_SWITCH_ID} or {CONF_VALVE_ON_SWITCH_ID} when using {CONF_VALVE_SWITCH_ID}"
)
if CONF_VALVE_PULSE_DURATION not in sprinkler_controller and (
CONF_VALVE_OFF_SWITCH_ID in valve or CONF_VALVE_ON_SWITCH_ID in valve
):
raise cv.Invalid(
f"{CONF_VALVE_PULSE_DURATION} must be specified when using {CONF_VALVE_OFF_SWITCH_ID} and {CONF_VALVE_ON_SWITCH_ID}"
)
if (
CONF_VALVE_SWITCH_ID not in valve
and CONF_VALVE_OFF_SWITCH_ID not in valve
and CONF_VALVE_ON_SWITCH_ID not in valve
):
raise cv.Invalid(
f"Either {CONF_VALVE_SWITCH_ID} or {CONF_VALVE_OFF_SWITCH_ID} and {CONF_VALVE_ON_SWITCH_ID} must be specified in valve configuration"
f"{CONF_VALVE_SWITCH_ID} must be specified in valve configuration"
)
if CONF_RUN_DURATION not in valve and CONF_RUN_DURATION_NUMBER not in valve:
raise cv.Invalid(
@@ -290,8 +245,15 @@ SPRINKLER_VALVE_SCHEMA = cv.Schema(
),
key=CONF_NAME,
),
cv.Optional(CONF_PUMP_OFF_SWITCH_ID): cv.use_id(switch.Switch),
cv.Optional(CONF_PUMP_ON_SWITCH_ID): cv.use_id(switch.Switch),
# Removed latching pump keys - accepted for validation error reporting
cv.Optional(CONF_PUMP_OFF_SWITCH_ID): cv.invalid(
f"This option was removed in 2026.1.0; for latching pumps, use {CONF_PUMP_SWITCH_ID} with an H-Bridge switch. "
f"See {docs_url('components/switch/h_bridge')} for more information"
),
cv.Optional(CONF_PUMP_ON_SWITCH_ID): cv.invalid(
f"This option was removed in 2026.1.0; for latching pumps, use {CONF_PUMP_SWITCH_ID} with an H-Bridge switch. "
f"See {docs_url('components/switch/h_bridge')} for more information"
),
cv.Optional(CONF_PUMP_SWITCH_ID): cv.use_id(switch.Switch),
cv.Optional(CONF_RUN_DURATION): cv.positive_time_period_seconds,
cv.Optional(CONF_RUN_DURATION_NUMBER): cv.maybe_simple_value(
@@ -321,8 +283,15 @@ SPRINKLER_VALVE_SCHEMA = cv.Schema(
switch.switch_schema(SprinklerControllerSwitch),
key=CONF_NAME,
),
cv.Optional(CONF_VALVE_OFF_SWITCH_ID): cv.use_id(switch.Switch),
cv.Optional(CONF_VALVE_ON_SWITCH_ID): cv.use_id(switch.Switch),
# Removed latching valve keys - accepted for validation error reporting
cv.Optional(CONF_VALVE_OFF_SWITCH_ID): cv.invalid(
f"This option was removed in 2026.1.0; for latching valves, use {CONF_VALVE_SWITCH_ID} with an H-Bridge switch. "
f"See {docs_url('components/switch/h_bridge')} for more information"
),
cv.Optional(CONF_VALVE_ON_SWITCH_ID): cv.invalid(
f"This option was removed in 2026.1.0; for latching valves, use {CONF_VALVE_SWITCH_ID} with an H-Bridge switch. "
f"See {docs_url('components/switch/h_bridge')} for more information"
),
cv.Optional(CONF_VALVE_SWITCH_ID): cv.use_id(switch.Switch),
}
)
@@ -410,8 +379,15 @@ SPRINKLER_CONTROLLER_SCHEMA = cv.Schema(
validate_min_max,
key=CONF_NAME,
),
cv.Optional(CONF_PUMP_PULSE_DURATION): cv.positive_time_period_milliseconds,
cv.Optional(CONF_VALVE_PULSE_DURATION): cv.positive_time_period_milliseconds,
# Removed latching valve keys - accepted for validation error reporting
cv.Optional(CONF_PUMP_PULSE_DURATION): cv.invalid(
f"This option was removed in 2026.1.0; for latching pumps, use {CONF_PUMP_SWITCH_ID} with an H-Bridge switch. "
f"See {docs_url('components/switch/h_bridge')} for more information"
),
cv.Optional(CONF_VALVE_PULSE_DURATION): cv.invalid(
f"This option was removed in 2026.1.0; for latching valves, use {CONF_VALVE_SWITCH_ID} with an H-Bridge switch. "
f"See {docs_url('components/switch/h_bridge')} for more information"
),
cv.Exclusive(
CONF_PUMP_START_PUMP_DELAY, "pump_start_xxxx_delay"
): cv.positive_time_period_seconds,
@@ -765,35 +741,10 @@ async def to_code(config):
valve_index, valve_switch, valve[CONF_RUN_DURATION]
)
)
elif CONF_VALVE_OFF_SWITCH_ID in valve and CONF_VALVE_ON_SWITCH_ID in valve:
valve_switch_off = await cg.get_variable(
valve[CONF_VALVE_OFF_SWITCH_ID]
)
valve_switch_on = await cg.get_variable(valve[CONF_VALVE_ON_SWITCH_ID])
cg.add(
var.configure_valve_switch_pulsed(
valve_index,
valve_switch_off,
valve_switch_on,
sprinkler_controller[CONF_VALVE_PULSE_DURATION],
valve[CONF_RUN_DURATION],
)
)
if CONF_PUMP_SWITCH_ID in valve:
pump = await cg.get_variable(valve[CONF_PUMP_SWITCH_ID])
cg.add(var.configure_valve_pump_switch(valve_index, pump))
elif CONF_PUMP_OFF_SWITCH_ID in valve and CONF_PUMP_ON_SWITCH_ID in valve:
pump_off = await cg.get_variable(valve[CONF_PUMP_OFF_SWITCH_ID])
pump_on = await cg.get_variable(valve[CONF_PUMP_ON_SWITCH_ID])
cg.add(
var.configure_valve_pump_switch_pulsed(
valve_index,
pump_off,
pump_on,
sprinkler_controller[CONF_PUMP_PULSE_DURATION],
)
)
if CONF_RUN_DURATION_NUMBER in valve:
num_rd_var = await number.new_number(

View File

@@ -11,70 +11,6 @@ namespace esphome::sprinkler {
static const char *const TAG = "sprinkler";
SprinklerSwitch::SprinklerSwitch() {}
SprinklerSwitch::SprinklerSwitch(switch_::Switch *sprinkler_switch) : on_switch_(sprinkler_switch) {}
SprinklerSwitch::SprinklerSwitch(switch_::Switch *off_switch, switch_::Switch *on_switch, uint32_t pulse_duration)
: pulse_duration_(pulse_duration), off_switch_(off_switch), on_switch_(on_switch) {}
bool SprinklerSwitch::is_latching_valve() { return (this->off_switch_ != nullptr) && (this->on_switch_ != nullptr); }
void SprinklerSwitch::loop() {
if ((this->pinned_millis_) && (App.get_loop_component_start_time() > this->pinned_millis_ + this->pulse_duration_)) {
this->pinned_millis_ = 0; // reset tracker
if (this->off_switch_->state) {
this->off_switch_->turn_off();
}
if (this->on_switch_->state) {
this->on_switch_->turn_off();
}
}
}
void SprinklerSwitch::turn_off() {
if (!this->state()) { // do nothing if we're already in the requested state
return;
}
if (this->off_switch_ != nullptr) { // latching valve, start a pulse
if (!this->off_switch_->state) {
this->off_switch_->turn_on();
}
this->pinned_millis_ = millis();
} else if (this->on_switch_ != nullptr) { // non-latching valve
this->on_switch_->turn_off();
}
this->state_ = false;
}
void SprinklerSwitch::turn_on() {
if (this->state()) { // do nothing if we're already in the requested state
return;
}
if (this->off_switch_ != nullptr) { // latching valve, start a pulse
if (!this->on_switch_->state) {
this->on_switch_->turn_on();
}
this->pinned_millis_ = millis();
} else if (this->on_switch_ != nullptr) { // non-latching valve
this->on_switch_->turn_on();
}
this->state_ = true;
}
bool SprinklerSwitch::state() {
if ((this->off_switch_ == nullptr) && (this->on_switch_ != nullptr)) { // latching valve is not configured...
return this->on_switch_->state; // ...so just return the pump switch state
}
return this->state_;
}
void SprinklerSwitch::sync_valve_state(bool latch_state) {
if (this->is_latching_valve()) {
this->state_ = latch_state;
} else if (this->on_switch_ != nullptr) {
this->state_ = this->on_switch_->state;
}
}
void SprinklerControllerNumber::setup() {
float value;
if (!this->restore_value_) {
@@ -219,8 +155,8 @@ void SprinklerValveOperator::start() {
this->state_ = STARTING; // STARTING state requires both a pump and a start_delay_
if (this->start_delay_is_valve_delay_) {
this->pump_on_();
} else if (!this->pump_switch()->state()) { // if the pump is already on, wait to switch on the valve
this->valve_on_(); // to ensure consistent run time
} else if (!this->pump_switch()->state) { // if the pump is already on, wait to switch on the valve
this->valve_on_(); // to ensure consistent run time
}
} else {
this->run_(); // there is no start_delay_, so just start the pump and valve
@@ -240,8 +176,8 @@ void SprinklerValveOperator::stop() {
} else {
this->valve_off_();
}
if (this->pump_switch()->state()) { // if the pump is still on at this point, it may be in use...
this->valve_off_(); // ...so just switch the valve off now to ensure consistent run time
if (this->pump_switch()->state) { // if the pump is still on at this point, it may be in use...
this->valve_off_(); // ...so just switch the valve off now to ensure consistent run time
}
} else {
this->kill_(); // there is no stop_delay_, so just stop the pump and valve
@@ -274,7 +210,7 @@ uint32_t SprinklerValveOperator::time_remaining() {
SprinklerState SprinklerValveOperator::state() { return this->state_; }
SprinklerSwitch *SprinklerValveOperator::pump_switch() {
switch_::Switch *SprinklerValveOperator::pump_switch() {
if ((this->controller_ == nullptr) || (this->valve_ == nullptr)) {
return nullptr;
}
@@ -285,48 +221,50 @@ SprinklerSwitch *SprinklerValveOperator::pump_switch() {
}
void SprinklerValveOperator::pump_off_() {
if ((this->valve_ == nullptr) || (this->pump_switch() == nullptr)) { // safety first!
auto *pump = this->pump_switch();
if ((this->valve_ == nullptr) || (pump == nullptr)) { // safety first!
return;
}
if (this->controller_ == nullptr) { // safety first!
this->pump_switch()->turn_off(); // if no controller was set, just switch off the pump
pump->turn_off(); // if no controller was set, just switch off the pump
} else { // ...otherwise, do it "safely"
auto state = this->state_; // this is silly, but...
this->state_ = BYPASS; // ...exclude me from the pump-in-use check that set_pump_state() does
this->controller_->set_pump_state(this->pump_switch(), false);
this->controller_->set_pump_state(pump, false);
this->state_ = state;
}
}
void SprinklerValveOperator::pump_on_() {
if ((this->valve_ == nullptr) || (this->pump_switch() == nullptr)) { // safety first!
auto *pump = this->pump_switch();
if ((this->valve_ == nullptr) || (pump == nullptr)) { // safety first!
return;
}
if (this->controller_ == nullptr) { // safety first!
this->pump_switch()->turn_on(); // if no controller was set, just switch on the pump
pump->turn_on(); // if no controller was set, just switch on the pump
} else { // ...otherwise, do it "safely"
auto state = this->state_; // this is silly, but...
this->state_ = BYPASS; // ...exclude me from the pump-in-use check that set_pump_state() does
this->controller_->set_pump_state(this->pump_switch(), true);
this->controller_->set_pump_state(pump, true);
this->state_ = state;
}
}
void SprinklerValveOperator::valve_off_() {
if (this->valve_ == nullptr) { // safety first!
if ((this->valve_ == nullptr) || (this->valve_->valve_switch == nullptr)) { // safety first!
return;
}
if (this->valve_->valve_switch.state()) {
this->valve_->valve_switch.turn_off();
if (this->valve_->valve_switch->state) {
this->valve_->valve_switch->turn_off();
}
}
void SprinklerValveOperator::valve_on_() {
if (this->valve_ == nullptr) { // safety first!
if ((this->valve_ == nullptr) || (this->valve_->valve_switch == nullptr)) { // safety first!
return;
}
if (!this->valve_->valve_switch.state()) {
this->valve_->valve_switch.turn_on();
if (!this->valve_->valve_switch->state) {
this->valve_->valve_switch->turn_on();
}
}
@@ -401,12 +339,6 @@ Sprinkler::Sprinkler(const std::string &name) {
void Sprinkler::setup() { this->all_valves_off_(true); }
void Sprinkler::loop() {
for (auto &p : this->pump_) {
p.loop();
}
for (auto &v : this->valve_) {
v.valve_switch.loop();
}
for (auto &vo : this->valve_op_) {
vo.loop();
}
@@ -423,10 +355,15 @@ void Sprinkler::add_valve(SprinklerControllerSwitch *valve_sw, SprinklerControll
new_valve->controller_switch = valve_sw;
new_valve->controller_switch->set_state_lambda([this, new_valve_number]() -> optional<bool> {
if (this->valve_pump_switch(new_valve_number) != nullptr) {
return this->valve_switch(new_valve_number)->state() && this->valve_pump_switch(new_valve_number)->state();
auto *valve = this->valve_switch(new_valve_number);
auto *pump = this->valve_pump_switch(new_valve_number);
if (valve == nullptr) {
return false;
}
return this->valve_switch(new_valve_number)->state();
if (pump != nullptr) {
return valve->state && pump->state;
}
return valve->state;
});
new_valve->valve_turn_off_automation =
@@ -496,18 +433,7 @@ void Sprinkler::set_controller_repeat_number(SprinklerControllerNumber *repeat_n
void Sprinkler::configure_valve_switch(size_t valve_number, switch_::Switch *valve_switch, uint32_t run_duration) {
if (this->is_a_valid_valve(valve_number)) {
this->valve_[valve_number].valve_switch.set_on_switch(valve_switch);
this->valve_[valve_number].run_duration = run_duration;
}
}
void Sprinkler::configure_valve_switch_pulsed(size_t valve_number, switch_::Switch *valve_switch_off,
switch_::Switch *valve_switch_on, uint32_t pulse_duration,
uint32_t run_duration) {
if (this->is_a_valid_valve(valve_number)) {
this->valve_[valve_number].valve_switch.set_off_switch(valve_switch_off);
this->valve_[valve_number].valve_switch.set_on_switch(valve_switch_on);
this->valve_[valve_number].valve_switch.set_pulse_duration(pulse_duration);
this->valve_[valve_number].valve_switch = valve_switch;
this->valve_[valve_number].run_duration = run_duration;
}
}
@@ -515,31 +441,12 @@ void Sprinkler::configure_valve_switch_pulsed(size_t valve_number, switch_::Swit
void Sprinkler::configure_valve_pump_switch(size_t valve_number, switch_::Switch *pump_switch) {
if (this->is_a_valid_valve(valve_number)) {
for (size_t i = 0; i < this->pump_.size(); i++) { // check each existing registered pump
if (this->pump_[i].on_switch() == pump_switch) { // if the "new" pump matches one we already have...
this->valve_[valve_number].pump_switch_index = i; // ...save its index in the SprinklerSwitch vector pump_...
if (this->pump_[i] == pump_switch) { // if the "new" pump matches one we already have...
this->valve_[valve_number].pump_switch_index = i; // ...save its index in the pump vector...
return; // ...and we are done
}
} // if we end up here, no pumps matched, so add a new one and set the valve's SprinklerSwitch at it
this->pump_.resize(this->pump_.size() + 1);
this->pump_.back().set_on_switch(pump_switch);
this->valve_[valve_number].pump_switch_index = this->pump_.size() - 1; // save the index to the new pump
}
}
void Sprinkler::configure_valve_pump_switch_pulsed(size_t valve_number, switch_::Switch *pump_switch_off,
switch_::Switch *pump_switch_on, uint32_t pulse_duration) {
if (this->is_a_valid_valve(valve_number)) {
for (size_t i = 0; i < this->pump_.size(); i++) { // check each existing registered pump
if ((this->pump_[i].off_switch() == pump_switch_off) &&
(this->pump_[i].on_switch() == pump_switch_on)) { // if the "new" pump matches one we already have...
this->valve_[valve_number].pump_switch_index = i; // ...save its index in the SprinklerSwitch vector pump_...
return; // ...and we are done
}
} // if we end up here, no pumps matched, so add a new one and set the valve's SprinklerSwitch at it
this->pump_.resize(this->pump_.size() + 1);
this->pump_.back().set_off_switch(pump_switch_off);
this->pump_.back().set_on_switch(pump_switch_on);
this->pump_.back().set_pulse_duration(pulse_duration);
} // if we end up here, no pumps matched, so add a new one
this->pump_.push_back(pump_switch);
this->valve_[valve_number].pump_switch_index = this->pump_.size() - 1; // save the index to the new pump
}
}
@@ -1041,7 +948,7 @@ size_t Sprinkler::number_of_valves() { return this->valve_.size(); }
bool Sprinkler::is_a_valid_valve(const size_t valve_number) { return (valve_number < this->number_of_valves()); }
bool Sprinkler::pump_in_use(SprinklerSwitch *pump_switch) {
bool Sprinkler::pump_in_use(switch_::Switch *pump_switch) {
if (pump_switch == nullptr) {
return false; // we can't do anything if there's nothing to check
}
@@ -1054,8 +961,7 @@ bool Sprinkler::pump_in_use(SprinklerSwitch *pump_switch) {
for (auto &vo : this->valve_op_) { // first, check if any SprinklerValveOperator has a valve dependent on this pump
if ((vo.state() != BYPASS) && (vo.pump_switch() != nullptr)) {
// the SprinklerValveOperator is configured with a pump; now check if it is the pump of interest
if ((vo.pump_switch()->off_switch() == pump_switch->off_switch()) &&
(vo.pump_switch()->on_switch() == pump_switch->on_switch())) {
if (vo.pump_switch() == pump_switch) {
// now if the SprinklerValveOperator has a pump and it is either ACTIVE, is STARTING with a valve delay or
// is STOPPING with a valve delay, its pump can be considered "in use", so just return indicating this now
if ((vo.state() == ACTIVE) ||
@@ -1074,13 +980,12 @@ bool Sprinkler::pump_in_use(SprinklerSwitch *pump_switch) {
if (valve_pump == nullptr) {
return false; // valve has no pump, so this pump isn't in use by it
}
return (pump_switch->off_switch() == valve_pump->off_switch()) &&
(pump_switch->on_switch() == valve_pump->on_switch());
return pump_switch == valve_pump;
}
return false;
}
void Sprinkler::set_pump_state(SprinklerSwitch *pump_switch, bool state) {
void Sprinkler::set_pump_state(switch_::Switch *pump_switch, bool state) {
if (pump_switch == nullptr) {
return; // we can't do anything if there's nothing to check
}
@@ -1091,15 +996,10 @@ void Sprinkler::set_pump_state(SprinklerSwitch *pump_switch, bool state) {
if (controller != this) { // dummy check
if (controller->pump_in_use(pump_switch)) {
hold_pump_on = true; // if another controller says it's using this pump, keep it on
// at this point we know if there exists another SprinklerSwitch that is "on" with its
// off_switch_ and on_switch_ pointers pointing to the same pair of switch objects
}
}
}
if (hold_pump_on) {
// at this point we know if there exists another SprinklerSwitch that is "on" with its
// off_switch_ and on_switch_ pointers pointing to the same pair of switch objects...
pump_switch->sync_valve_state(true); // ...so ensure our state is consistent
ESP_LOGD(TAG, "Leaving pump on because another controller instance is using it");
}
@@ -1107,8 +1007,6 @@ void Sprinkler::set_pump_state(SprinklerSwitch *pump_switch, bool state) {
pump_switch->turn_on();
} else if (!hold_pump_on && !this->pump_in_use(pump_switch)) {
pump_switch->turn_off();
} else if (hold_pump_on) { // we must assume the other controller will switch off the pump when done...
pump_switch->sync_valve_state(false); // ...this only impacts latching valves
}
}
@@ -1274,23 +1172,23 @@ SprinklerControllerSwitch *Sprinkler::enable_switch(size_t valve_number) {
return nullptr;
}
SprinklerSwitch *Sprinkler::valve_switch(const size_t valve_number) {
switch_::Switch *Sprinkler::valve_switch(const size_t valve_number) {
if (this->is_a_valid_valve(valve_number)) {
return &this->valve_[valve_number].valve_switch;
return this->valve_[valve_number].valve_switch;
}
return nullptr;
}
SprinklerSwitch *Sprinkler::valve_pump_switch(const size_t valve_number) {
switch_::Switch *Sprinkler::valve_pump_switch(const size_t valve_number) {
if (this->is_a_valid_valve(valve_number) && this->valve_[valve_number].pump_switch_index.has_value()) {
return &this->pump_[this->valve_[valve_number].pump_switch_index.value()];
return this->pump_[this->valve_[valve_number].pump_switch_index.value()];
}
return nullptr;
}
SprinklerSwitch *Sprinkler::valve_pump_switch_by_pump_index(size_t pump_index) {
switch_::Switch *Sprinkler::valve_pump_switch_by_pump_index(size_t pump_index) {
if (pump_index < this->pump_.size()) {
return &this->pump_[pump_index];
return this->pump_[pump_index];
}
return nullptr;
}
@@ -1454,8 +1352,9 @@ void Sprinkler::start_valve_(SprinklerValveRunRequest *req) {
void Sprinkler::all_valves_off_(const bool include_pump) {
for (size_t valve_index = 0; valve_index < this->number_of_valves(); valve_index++) {
if (this->valve_[valve_index].valve_switch.state()) {
this->valve_[valve_index].valve_switch.turn_off();
auto *valve_sw = this->valve_[valve_index].valve_switch;
if ((valve_sw != nullptr) && valve_sw->state) {
valve_sw->turn_off();
}
if (include_pump) {
this->set_pump_state(this->valve_pump_switch(valve_index), false);
@@ -1754,10 +1653,6 @@ void Sprinkler::dump_config() {
" Name: %s\n"
" Run Duration: %" PRIu32 " seconds",
valve_number, this->valve_name(valve_number), this->valve_run_duration(valve_number));
if (this->valve_[valve_number].valve_switch.pulse_duration()) {
ESP_LOGCONFIG(TAG, " Pulse Duration: %" PRIu32 " milliseconds",
this->valve_[valve_number].valve_switch.pulse_duration());
}
}
if (!this->pump_.empty()) {
ESP_LOGCONFIG(TAG, " Total number of pumps: %zu", this->pump_.size());

View File

@@ -35,7 +35,6 @@ enum SprinklerValveRunRequestOrigin : uint8_t {
class Sprinkler; // this component
class SprinklerControllerNumber; // number components that appear in the front end; based on number core
class SprinklerControllerSwitch; // switches that appear in the front end; based on switch core
class SprinklerSwitch; // switches representing any valve or pump; provides abstraction for latching valves
class SprinklerValveOperator; // manages all switching on/off of valves and associated pumps
class SprinklerValveRunRequest; // tells the sprinkler controller what valve to run and for how long as well as what
// SprinklerValveOperator is handling it
@@ -43,34 +42,6 @@ template<typename... Ts> class StartSingleValveAction;
template<typename... Ts> class ShutdownAction;
template<typename... Ts> class ResumeOrStartAction;
class SprinklerSwitch {
public:
SprinklerSwitch();
SprinklerSwitch(switch_::Switch *sprinkler_switch);
SprinklerSwitch(switch_::Switch *off_switch, switch_::Switch *on_switch, uint32_t pulse_duration);
bool is_latching_valve(); // returns true if configured as a latching valve
void loop(); // called as a part of loop(), used for latching valve pulses
uint32_t pulse_duration() { return this->pulse_duration_; }
bool state(); // returns the switch's current state
void set_off_switch(switch_::Switch *off_switch) { this->off_switch_ = off_switch; }
void set_on_switch(switch_::Switch *on_switch) { this->on_switch_ = on_switch; }
void set_pulse_duration(uint32_t pulse_duration) { this->pulse_duration_ = pulse_duration; }
void sync_valve_state(
bool latch_state); // syncs internal state to switch; if latching valve, sets state to latch_state
void turn_off(); // sets internal flag and actuates the switch
void turn_on(); // sets internal flag and actuates the switch
switch_::Switch *off_switch() { return this->off_switch_; }
switch_::Switch *on_switch() { return this->on_switch_; }
protected:
bool state_{false};
uint32_t pulse_duration_{0};
uint64_t pinned_millis_{0};
switch_::Switch *off_switch_{nullptr}; // only used for latching valves
switch_::Switch *on_switch_{nullptr}; // used for both latching and non-latching valves
};
struct SprinklerQueueItem {
size_t valve_number;
uint32_t run_duration;
@@ -88,7 +59,7 @@ struct SprinklerValve {
SprinklerControllerNumber *run_duration_number;
SprinklerControllerSwitch *controller_switch;
SprinklerControllerSwitch *enable_switch;
SprinklerSwitch valve_switch;
switch_::Switch *valve_switch;
uint32_t run_duration;
optional<size_t> pump_switch_index;
bool valve_cycle_complete;
@@ -155,7 +126,7 @@ class SprinklerValveOperator {
uint32_t run_duration(); // returns the desired run duration in seconds
uint32_t time_remaining(); // returns seconds remaining (does not include stop_delay_)
SprinklerState state(); // returns the valve's state/status
SprinklerSwitch *pump_switch(); // returns this SprinklerValveOperator's pump's SprinklerSwitch
switch_::Switch *pump_switch(); // returns this SprinklerValveOperator's pump switch
protected:
void pump_off_();
@@ -228,13 +199,9 @@ class Sprinkler : public Component {
/// configure a valve's switch object and run duration. run_duration is time in seconds.
void configure_valve_switch(size_t valve_number, switch_::Switch *valve_switch, uint32_t run_duration);
void configure_valve_switch_pulsed(size_t valve_number, switch_::Switch *valve_switch_off,
switch_::Switch *valve_switch_on, uint32_t pulse_duration, uint32_t run_duration);
/// configure a valve's associated pump switch object
void configure_valve_pump_switch(size_t valve_number, switch_::Switch *pump_switch);
void configure_valve_pump_switch_pulsed(size_t valve_number, switch_::Switch *pump_switch_off,
switch_::Switch *pump_switch_on, uint32_t pulse_duration);
/// configure a valve's run duration number component
void configure_valve_run_duration_number(size_t valve_number, SprinklerControllerNumber *run_duration_number);
@@ -383,10 +350,10 @@ class Sprinkler : public Component {
bool is_a_valid_valve(size_t valve_number);
/// returns true if the pump the pointer points to is in use
bool pump_in_use(SprinklerSwitch *pump_switch);
bool pump_in_use(switch_::Switch *pump_switch);
/// switches on/off a pump "safely" by checking that the new state will not conflict with another controller
void set_pump_state(SprinklerSwitch *pump_switch, bool state);
void set_pump_state(switch_::Switch *pump_switch, bool state);
/// returns the amount of time in seconds required for all valves
uint32_t total_cycle_time_all_valves();
@@ -419,13 +386,13 @@ class Sprinkler : public Component {
SprinklerControllerSwitch *enable_switch(size_t valve_number);
/// returns a pointer to a valve's switch object
SprinklerSwitch *valve_switch(size_t valve_number);
switch_::Switch *valve_switch(size_t valve_number);
/// returns a pointer to a valve's pump switch object
SprinklerSwitch *valve_pump_switch(size_t valve_number);
switch_::Switch *valve_pump_switch(size_t valve_number);
/// returns a pointer to a valve's pump switch object
SprinklerSwitch *valve_pump_switch_by_pump_index(size_t pump_index);
switch_::Switch *valve_pump_switch_by_pump_index(size_t pump_index);
protected:
/// returns true if valve number is enabled
@@ -577,8 +544,8 @@ class Sprinkler : public Component {
/// Queue of valves to activate next, regardless of auto-advance
std::vector<SprinklerQueueItem> queued_valves_;
/// Sprinkler valve pump objects
std::vector<SprinklerSwitch> pump_;
/// Sprinkler valve pump switches
std::vector<switch_::Switch *> pump_;
/// Sprinkler valve objects
std::vector<SprinklerValve> valve_;