[sprinkler] Remove internal latching valve support (#12603)
This commit is contained in:
@@ -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(
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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_;
|
||||
|
||||
Reference in New Issue
Block a user