diff --git a/esp32/include/HomieConfiguration.h b/esp32/include/HomieConfiguration.h index e6873c4..6cad4ad 100644 --- a/esp32/include/HomieConfiguration.h +++ b/esp32/include/HomieConfiguration.h @@ -69,7 +69,7 @@ HomieNode stayAlive("stay", "alive", "alive"); /**< Necessary for Mqtt Active C HomieSetting deepSleepTime("sleep", "time in seconds to sleep"); HomieSetting deepSleepNightTime("nightsleep", "time in seconds to sleep (0 uses same setting: deepsleep at night, too)"); HomieSetting wateringDeepSleep("pumpsleep", "time seconds to sleep, while a pump is running"); - +HomieSetting pumpIneffectiveWarning("pumpConsecutiveWarn", "if the pump was triggered this amount directly after each cooldown, without resolving dryness, warn"); HomieSetting waterLevelMax("tankmax", "distance (mm) at maximum water level"); HomieSetting waterLevelMin("tankmin", "distance (mm) at minimum water level (pumps still covered)"); HomieSetting waterLevelWarn("tankwarn", "warn (mm) if below this water level %"); diff --git a/esp32/include/LogDefines.h b/esp32/include/LogDefines.h index 6dfb484..867ce44 100644 --- a/esp32/include/LogDefines.h +++ b/esp32/include/LogDefines.h @@ -20,6 +20,9 @@ #define LOG_PUMP_AND_DOWNLOADMODE "Download mode, ignoring pump request" #define LOG_PUMP_AND_DOWNLOADMODE_CODE 2 +//msg is dynamic defined +#define LOG_PUMP_INEFFECTIVE -4 + #define LOG_DEBUG_CODE 1001 #define LOG_NOPUMP_LOWLIGHT 100 #define LOG_NOPUMPS 101 diff --git a/esp32/src/PlantCtrl.cpp b/esp32/src/PlantCtrl.cpp index a46a497..e0cbd4d 100644 --- a/esp32/src/PlantCtrl.cpp +++ b/esp32/src/PlantCtrl.cpp @@ -121,7 +121,6 @@ void Plant::postMQTTconnection(void) this->mPlant->setProperty("moist").send(String(round(pct*10)/10)); this->mPlant->setProperty("moistraw").send(String(raw)); this->mPlant->setProperty("moisttrigger").send(String(getSetting2Moisture())); - } void Plant::deactivatePump(void) diff --git a/esp32/src/main.cpp b/esp32/src/main.cpp index 8cfcc76..2850e1d 100644 --- a/esp32/src/main.cpp +++ b/esp32/src/main.cpp @@ -34,7 +34,6 @@ #include #include - /****************************************************************************** * DEFINES ******************************************************************************/ @@ -70,6 +69,7 @@ RTC_DATA_ATTR int lastPumpRunning = -1; /**< store last successfully waterd plan RTC_DATA_ATTR long lastWaterValue = 0; /**< to calculate the used water per plant */ RTC_DATA_ATTR long rtcLastWateringPlant[MAX_PLANTS] = {0}; +RTC_DATA_ATTR long consecutiveWateringPlant[MAX_PLANTS] = {0}; /****************************************************************************** * LOCAL VARIABLES @@ -416,6 +416,11 @@ int determineNextPump() int pumpToUse = -1; for (int i = 0; i < MAX_PLANTS; i++) { + bool wateralarm = consecutiveWateringPlant[i] >= pumpIneffectiveWarning.get(); + if (wateralarm) + { + log(LOG_LEVEL_ERROR, String(String(i) + " Plant still dry after " + String(consecutiveWateringPlant[i]) + " watering attempts"), LOG_PUMP_INEFFECTIVE); + } Plant plant = mPlants[i]; if (!plant.isPumpTriggerActive()) { @@ -425,17 +430,32 @@ int determineNextPump() } if ((rtcLastWateringPlant[i] + plant.getCooldownInSeconds()) > getCurrentTime()) { - plant.publishState("cooldown"); + if (wateralarm) + { + plant.publishState("cooldown+alarm"); + } + else + { + plant.publishState("cooldown"); + } log(LOG_LEVEL_DEBUG, String(String(i) + " Skipping due to cooldown " + String(rtcLastWateringPlant[i] + plant.getCooldownInSeconds())), LOG_DEBUG_CODE); continue; } if (!isLowLight && plant.isAllowedOnlyAtLowLight()) { - plant.publishState("sunny"); + if (wateralarm) + { + plant.publishState("sunny+alarm"); + } + else + { + plant.publishState("sunny"); + } + log(LOG_LEVEL_DEBUG, String(String(i) + " No pump required: due to light"), LOG_DEBUG_CODE); continue; } - if (equalish(plant.getCurrentMoisture(),MISSING_SENSOR)) + if (equalish(plant.getCurrentMoisture(), MISSING_SENSOR)) { plant.publishState("nosensor"); log(LOG_LEVEL_ERROR, String(String(i) + " No pump possible: missing sensor"), LOG_MISSING_PUMP); @@ -452,13 +472,29 @@ int determineNextPump() /* no time from NTP received */ (getCurrentTime() < 10000)) { - plant.publishState("active"); + if (wateralarm) + { + plant.publishState("active+alarm"); + } + else + { + plant.publishState("active"); + } + + consecutiveWateringPlant[i]++; log(LOG_LEVEL_DEBUG, String(String(i) + " Requested pumping"), LOG_DEBUG_CODE); pumpToUse = i; } else { - plant.publishState("after-work"); + if (wateralarm) + { + plant.publishState("after-work+alarm"); + } + else + { + plant.publishState("after-work"); + } log(LOG_LEVEL_DEBUG, String(String(i) + " ignored due to time boundary: " + String(plant.getHoursStart()) + " to " + String(plant.getHoursEnd()) + " ( current " + String(getCurrentHour()) + " )"), LOG_DEBUG_CODE); } continue; @@ -466,6 +502,8 @@ int determineNextPump() else { plant.publishState("wet"); + //plant was detected as wet, remove consecutive count + consecutiveWateringPlant[i] = 0; } } return pumpToUse; @@ -513,31 +551,38 @@ void homieLoop() } } -bool switch1(const HomieRange& range, const String& value) { +bool switch1(const HomieRange &range, const String &value) +{ return mPlants[0].switchHandler(range, value); } -bool switch2(const HomieRange& range, const String& value) { +bool switch2(const HomieRange &range, const String &value) +{ return mPlants[1].switchHandler(range, value); } -bool switch3(const HomieRange& range, const String& value) { +bool switch3(const HomieRange &range, const String &value) +{ return mPlants[2].switchHandler(range, value); } -bool switch4(const HomieRange& range, const String& value) { +bool switch4(const HomieRange &range, const String &value) +{ return mPlants[3].switchHandler(range, value); } -bool switch5(const HomieRange& range, const String& value) { +bool switch5(const HomieRange &range, const String &value) +{ return mPlants[4].switchHandler(range, value); } -bool switch6(const HomieRange& range, const String& value) { +bool switch6(const HomieRange &range, const String &value) +{ return mPlants[5].switchHandler(range, value); } -bool switch7(const HomieRange& range, const String& value) { +bool switch7(const HomieRange &range, const String &value) +{ return mPlants[6].switchHandler(range, value); } @@ -626,7 +671,8 @@ void setup() // Set default values //in seconds - deepSleepTime.setDefaultValue(600).setValidator([](long candidate) { return (candidate > 0) && (candidate < (60 * 60 * 2) /** 2h max sleep */); }); + deepSleepTime.setDefaultValue(600).setValidator([](long candidate) + { return (candidate > 0) && (candidate < (60 * 60 * 2) /** 2h max sleep */); }); deepSleepNightTime.setDefaultValue(600); wateringDeepSleep.setDefaultValue(5); ntpServer.setDefaultValue("pool.ntp.org"); @@ -637,6 +683,9 @@ void setup() waterLevelVol.setDefaultValue(5000); /* 5l in ml */ lipoSensorAddr.setDefaultValue(""); waterSensorAddr.setDefaultValue(""); + pumpIneffectiveWarning.setDefaultValue(600).setValidator([](long candidate) + { return (candidate > 0) && (candidate < (20)); }); + pumpIneffectiveWarning.setDefaultValue(5); Homie.setLoopFunction(homieLoop); Homie.onEvent(onHomieEvent); @@ -802,6 +851,7 @@ void plantcontrol() for (int i = 0; i < MAX_PLANTS; i++) { mPlants[i].postMQTTconnection(); + mPlants[i].setProperty("consecutivePumps").send(String(consecutiveWateringPlant[i])); } } @@ -817,10 +867,12 @@ void plantcontrol() if (mAliveWasRead) { float remaining = waterLevelMax.get() - waterRawSensor.getAverage(); - if (! isnan(remaining)) { + if (!isnan(remaining)) + { sensorWater.setProperty("remaining").send(String(remaining)); } - if (! isnan(waterRawSensor.getAverage())) { + if (!isnan(waterRawSensor.getAverage())) + { sensorWater.setProperty("distance").send(String(waterRawSensor.getAverage())); } sensorLipo.setProperty("percent").send(String(100 * batteryVoltage / VOLT_MAX_BATT));