diff --git a/chlorPump.yaml b/chlorPump.yaml index 1ca6155..dd11919 100644 --- a/chlorPump.yaml +++ b/chlorPump.yaml @@ -185,8 +185,12 @@ chlorine_pump: id: chlorine_pump_component disable_clock: false proportional_band: 200 + cycle_time: 300 target: 700 # get_target: !lambda return id(chlorine_target).state; + cycle_modifiers: + min_on_time: 30 + max_on_time: 240 on_pump_value: - lambda: |- if(pState != id(last_pump_state)){ diff --git a/external_components/chlorine_pump/__init__.py b/external_components/chlorine_pump/__init__.py index 4c93cfb..14fdbbc 100644 --- a/external_components/chlorine_pump/__init__.py +++ b/external_components/chlorine_pump/__init__.py @@ -23,6 +23,12 @@ CONF_DISABLE_CLOCK="disable_clock" CONF_TARGET="target" CONF_TARGET_LAMBDA="get_target" CONF_PUMP_TIME_DIVIDER = "pump_time_divider" +CONF_CYCLE_MODIFIERS = "cycle_modifiers" +CONF_MIN_ON_TIME = "min_on_time" +CONF_MAX_ON_TIME = "max_on_time" +CONF_CYCLE_TIME_MULTIPLIER = "on_time_modifier" +CONF_CYCLE_TIME_OFFSET = "on_time_offset" +CONF_CYCLE_TIME_IGNORE_MAX_X_BELOW_TARGET = "ignore_max_x_below_target" def to_proportional_band(value): try: @@ -48,6 +54,19 @@ ManualDoseAction = chlorine_pump_ns.class_("ChlorineDose", automation.Action) def validate_config(config): if (config.get(CONF_TARGET_LAMBDA, None) is not None) is not (config.get(CONF_TARGET, None) not in config): raise cv.Invalid("Either a fixed target or an get_target lambda must be set to get a target") + if CONF_CYCLE_MODIFIERS in config: + cycle_mod = config.get(CONF_CYCLE_MODIFIERS) + if cycle_mod[CONF_MIN_ON_TIME] >= config[CONF_PUMP_CYCLE_TIME]: + raise cv.Invalid("min_on_time must be smaller than cycle_time(default = 360)") + if cycle_mod.get(CONF_MAX_ON_TIME) in cycle_mod and config[CONF_PUMP_CYCLE_TIME] < cycle_mod[CONF_MAX_ON_TIME]: + raise cv.Invalid("max_on_time must be smaller or equal cycle_time(default = 360)") + if cycle_mod.get(CONF_MAX_ON_TIME) in cycle_mod and cycle_mod[CONF_MIN_ON_TIME] >= cycle_mod[CONF_MAX_ON_TIME]: + raise cv.Invalid("min_on_time must be smaller than max_on_time") + if cycle_mod.get(CONF_CYCLE_TIME_OFFSET) >= config[CONF_PUMP_CYCLE_TIME]: + raise cv.Invalid("cycle_time_offset must be smaller than cycle_time(default = 360)") + if cycle_mod.get(CONF_CYCLE_TIME_IGNORE_MAX_X_BELOW_TARGET) in cycle_mod and cycle_mod[CONF_CYCLE_TIME_IGNORE_MAX_X_BELOW_TARGET] <= config[CONF_PUMP_PROPORTIONAL_BAND]: + raise cv.Invalid("ignore_max_x_below_target must larger than proportional_band(default = 200)") + return config CONFIG_SCHEMA = cv.All( @@ -61,6 +80,14 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_TARGET): cv.int_range(300, 1400), cv.Optional(CONF_PUMP_TIME_DIVIDER, 2): cv.float_range(1, 5), cv.Optional(CONF_TARGET_LAMBDA, 2): cv.templatable(cv.float_), + cv.Optional(CONF_CYCLE_MODIFIERS): cv.All({ + cv.Optional(CONF_MIN_ON_TIME, 0): cv.int_range(0, 1400), + cv.Optional(CONF_MAX_ON_TIME): cv.int_range(0, 1400), + cv.Optional(CONF_CYCLE_TIME_MULTIPLIER, 1): cv.float_range(0.01, 5.0), + cv.Optional(CONF_CYCLE_TIME_OFFSET, 0): cv.int_range(0, 1400), + cv.Optional(CONF_CYCLE_TIME_IGNORE_MAX_X_BELOW_TARGET): cv.int_range(100 - 1500), + }), + cv.Optional(CONF_PUMP_VALUE): automation.validate_automation({ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ChlorSensorOutputTrigger), } @@ -69,6 +96,7 @@ CONFIG_SCHEMA = cv.All( cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ChlorSensorCycleTrigger), } ), + }), validate_config ) @@ -132,6 +160,16 @@ async def to_code(config): #prop_band = yield cg.get_variable(config[CONF_PUMP_PROPORTIONAL_BAND]) cg.add(var.set_prop_band(config[CONF_PUMP_PROPORTIONAL_BAND])) + if CONF_CYCLE_MODIFIERS in config: + conf = config.get(CONF_CYCLE_MODIFIERS) + cg.add(var.set_min_on_time(conf[CONF_MIN_ON_TIME])) + cg.add(var.set_time_multiplier(conf[CONF_CYCLE_TIME_MULTIPLIER])) + cg.add(var.set_time_offset(conf[CONF_CYCLE_TIME_OFFSET])) + if CONF_MAX_ON_TIME in conf: + cg.add(var.set_max_on_time(conf[CONF_MAX_ON_TIME])) + if CONF_CYCLE_TIME_IGNORE_MAX_X_BELOW_TARGET in conf: + cg.add(var.set_ignore_max_x_below_target(conf[CONF_CYCLE_TIME_IGNORE_MAX_X_BELOW_TARGET])) + #cg.add(var.set_state(config[CONF_STATE])) if CONF_TARGET not in config: template_ = await cg.templatable(config[CONF_TARGET_LAMBDA], [], float) diff --git a/external_components/chlorine_pump/pump_cycle.h b/external_components/chlorine_pump/pump_cycle.h index b663dac..2ccf931 100644 --- a/external_components/chlorine_pump/pump_cycle.h +++ b/external_components/chlorine_pump/pump_cycle.h @@ -2,6 +2,7 @@ #include "esphome/core/automation.h" #include "esphome/components/output/binary_output.h" +#include "Arduino.h" static const char *const TAG = "chlorine_pump"; @@ -26,13 +27,18 @@ class ChlorinePump : public Component { float tOn_divider_; std::function target_lambda_ = nullptr; + int min_on_time_ = 0; + int max_on_time_ = -1; + float on_time_multiplier_ = 1; + int on_time_offset_ = 0; + int ignore_max_x_below_target_ = -1; + public: ChlorinePump(){ last_action = 0; } - void disable_clock(bool disable_clock){ this->disable_clock_ = disable_clock; } @@ -55,6 +61,23 @@ class ChlorinePump : public Component { this->target_ = target; } + // Cycle Time Modifiers + void set_min_on_time(int min_on_time){ + this->min_on_time_ = min_on_time; + } + void set_max_on_time(int max_on_time){ + this->max_on_time_ = max_on_time; + } + void set_time_multiplier(float time_multi){ + this->on_time_multiplier_ = time_multi; + } + void set_time_offset(int offset){ + this->on_time_offset_ = offset; + } + void set_ignore_max_x_below_target(int set_below){ + this->ignore_max_x_below_target_ = set_below; + } + void setup() override { last_action = millis(); if(disable_clock_ && sensor_ != nullptr){ @@ -120,7 +143,19 @@ class ChlorinePump : public Component { return (int) timeInSeconds; } - + int calculate_changed_on_time(int tOn, float last_mesurement){ + + if(ignore_max_x_below_target_ != -1 && (float)(target_ - ignore_max_x_below_target_) >= last_mesurement){ + return cycle_time; + } + tOn = (int)((float) tOn * on_time_multiplier_); + tOn += on_time_offset_; + + if(tOn < min_on_time_) tOn = min_on_time_; + if(max_on_time_ != -1 && tOn > max_on_time_) tOn = max_on_time_; + + return tOn; + } void add_on_pump_callback(std::function &&callback){ this->callback_pump_.add(std::move(callback)); @@ -134,7 +169,10 @@ class ChlorinePump : public Component { if(tOn == 0 && tOff == 0 && state){ int seconds = calculatePumpTimeSeconds(last_mesurement); - tOn = seconds; + if(seconds != 0) + tOn = calculate_changed_on_time(seconds, last_mesurement); + else + tOn = 0; tOff = cycle_time - tOn; if(seconds == 0){ diff --git a/external_components/ezo_orp_i2c/ezo_orp.cpp b/external_components/ezo_orp_i2c/ezo_orp.cpp index fad30f1..6a6257e 100644 --- a/external_components/ezo_orp_i2c/ezo_orp.cpp +++ b/external_components/ezo_orp_i2c/ezo_orp.cpp @@ -42,11 +42,15 @@ void EzoOrpSensor::read_response(int maxLength, SensorAction action) { if(i2c::ERROR_OK != this->read(data, maxLength)){ ESP_LOGW(TAG, "Error Occured while reading respnse!"); + busy_ = false; + runScheduledAction(); return; } if(data[0] != 1 && data[0] != 255){ ESP_LOGW(TAG, "Read status code of %d, (Operation: %d)", data[0], action); + busy_ = false; + runScheduledAction(); return; }