diff --git a/esp32/PlantControl.code-workspace b/esp32/PlantControl.code-workspace index fadf157..a513b43 100644 --- a/esp32/PlantControl.code-workspace +++ b/esp32/PlantControl.code-workspace @@ -12,7 +12,8 @@ "istream": "cpp", "limits": "cpp", "streambuf": "cpp", - "functional": "cpp" + "functional": "cpp", + "string": "cpp" } } } diff --git a/esp32/include/ControllerConfiguration.h b/esp32/include/ControllerConfiguration.h index 4c2520b..e099349 100644 --- a/esp32/include/ControllerConfiguration.h +++ b/esp32/include/ControllerConfiguration.h @@ -47,7 +47,8 @@ #define MIN_TIME_RUNNING 5UL /**< Amount of seconds the controller must stay awoken */ #define MAX_PLANTS 7 #define EMPTY_LIPO_MULTIPL 3 /**< Multiplier to increase time for sleeping when lipo is empty */ -#define MINIMUM_LIPO_VOLT 3.3f /**< Minimum voltage of the Lipo, that must be present */ +#define MINIMUM_LIPO_VOLT 3.6f /**< Minimum voltage of the Lipo, that must be present */ +#define NO_LIPO_VOLT 2.0f /**< No Lipo connected */ #define MINIMUM_SOLAR_VOLT 4.0f /**< Minimum voltage of the sun, to detect daylight */ #define HC_SR04 /**< Ultrasonic distance sensor to measure water level */ diff --git a/esp32/include/PlantCtrl.h b/esp32/include/PlantCtrl.h index da7a22d..df1a914 100644 --- a/esp32/include/PlantCtrl.h +++ b/esp32/include/PlantCtrl.h @@ -25,9 +25,12 @@ private: int mAnalogValue=0; /**< moist sensor values, used for a calculation */ HomieNode *mPlant = NULL; - HomieSetting *mSensorTriggerLevel=NULL; - HomieSetting *mWateringTime=NULL; - HomieSetting *mWateringIdleTime=NULL; + HomieSetting *mSensorDry; + HomieSetting *mSensorWet; + HomieSetting *mPumpAllowedHourRangeStart; + HomieSetting *mPumpAllowedHourRangeEnd; + HomieSetting *mPumpOnlyWhenLowLight; + HomieSetting *mPumpCooldownInHours; public: @@ -38,10 +41,7 @@ public: * @param pinPump Pin of the Pump to use */ Plant(int pinSensor, int pinPump, - HomieNode *plant, - HomieSetting *sensorTriggerLevel, - HomieSetting *wateringTime, - HomieSetting *wateringIdleTime); + int plantId); /** * @brief Add a value, to be measured @@ -81,7 +81,7 @@ public: * @return false */ bool isPumpRequired() { - return (this->mSensorTriggerLevel != NULL) && (this->mValue < this->mSensorTriggerLevel->get()); + return (this->mSensorWet != NULL) && (this->mValue < this->mSensorWet->get()); } HomieInternals::SendingPromise& setProperty(const String& property) const { diff --git a/esp32/src/PlantCtrl.cpp b/esp32/src/PlantCtrl.cpp index 613afe4..fdba9cd 100644 --- a/esp32/src/PlantCtrl.cpp +++ b/esp32/src/PlantCtrl.cpp @@ -12,17 +12,63 @@ #include "PlantCtrl.h" -Plant::Plant(int pinSensor, int pinPump, - HomieNode *plant, - HomieSetting *sensorTriggerLevel, - HomieSetting *wateringTime, - HomieSetting *wateringIdleTime) { - this->mPlant=plant; - this->mPinSensor = pinSensor; - this->mPinPump = pinPump; - this->mSensorTriggerLevel=sensorTriggerLevel; - this->mWateringTime=wateringTime; - this->mWateringIdleTime=wateringIdleTime; +Plant::Plant(int pinSensor, int pinPump,int plantId) { + this->mPinSensor = pinSensor; + this->mPinPump = pinPump; + + char plantIdChar = plantId+'0'; + + { + char* name = "moistZdry"; + name[6]= plantIdChar; + mSensorDry = new HomieSetting(name, "Moist sensor dry threshold"); + mSensorDry->setDefaultValue(4095); + mSensorDry->setValidator([] (long candidate) { + return ((candidate >= 0) && (candidate <= 4095) ); + }); + } + { + char* name = "moistZwet"; + name[6]= plantIdChar; + mSensorWet = new HomieSetting(name, "Moist sensor wet threshold"); + mSensorWet->setDefaultValue(0); + mSensorWet->setValidator([] (long candidate) { + return ((candidate >= 0) && (candidate <= 4095) ); + }); + } + { + char* name = "rangeZhourstart"; + name[6]= plantIdChar; + mPumpAllowedHourRangeStart = new HomieSetting(name, "Range pump allowed hour start"); + mPumpAllowedHourRangeStart->setDefaultValue(8); + mPumpAllowedHourRangeStart->setValidator([] (long candidate) { + return ((candidate >= 0) && (candidate <= 23) ); + }); + } + { + char* name = "rangeZhourend"; + name[6]= plantIdChar; + mPumpAllowedHourRangeEnd = new HomieSetting(name, "Range pump allowed hour end"); + mPumpAllowedHourRangeEnd->setDefaultValue(20); + mPumpAllowedHourRangeEnd->setValidator([] (long candidate) { + return ((candidate >= 0) && (candidate <= 23) ); + }); + } + { + char* name = "onlyWhenLowLightZ"; + name[16]= plantIdChar; + mPumpOnlyWhenLowLight = new HomieSetting(name, "Enable the Pump only, when there is light but not enought to charge battery"); + mPumpOnlyWhenLowLight->setDefaultValue(true); + } + { + char* name = "cooldownpumpZ"; + name[12]= plantIdChar; + mPumpCooldownInHours = new HomieSetting(name, "How long to wait until the pump is activated again"); + mPumpCooldownInHours->setDefaultValue(20); + mPumpCooldownInHours->setValidator([] (long candidate) { + return ((candidate >= 0) && (candidate <= 1024) ); + }); + } } void Plant::addSenseValue(int analog) { diff --git a/esp32/src/main.cpp b/esp32/src/main.cpp index a446f39..4fa8096 100644 --- a/esp32/src/main.cpp +++ b/esp32/src/main.cpp @@ -73,44 +73,22 @@ HomieNode stayAlive("stay", "alive", "alive"); HomieSetting deepSleepTime("deepsleep", "time in milliseconds to sleep (0 deactivats it)"); HomieSetting deepSleepNightTime("nightsleep", "time in milliseconds to sleep (0 usese same setting: deepsleep at night, too)"); HomieSetting wateringDeepSleep("pumpdeepsleep", "time seconds to sleep, while a pump is running"); -HomieSetting plantCnt("plants", "amout of plants to control (1 ... 7)"); -#ifdef HC_SR04 -HomieSetting waterLevel("watermaxlevel", "Water maximum level in centimeter (50 cm default)"); -HomieSetting waterMinPercent("watermin", "Minimum percentage of water, to activate the pumps (default 5%)"); -#endif -HomieSetting plant0SensorTrigger("moist0", "Moist0 sensor dry "); -HomieSetting plant1SensorTrigger("moist1", "Moist1 sensor value, when pump activates"); -HomieSetting plant2SensorTrigger("moist2", "Moist2 sensor value, when pump activates"); -HomieSetting plant3SensorTrigger("moist3", "Moist3 sensor value, when pump activates"); -HomieSetting plant4SensorTrigger("moist4", "Moist4 sensor value, when pump activates"); -HomieSetting plant5SensorTrigger("moist5", "Moist5 sensor value, when pump activates"); -HomieSetting plant6SensorTrigger("moist6", "Moist6 sensor value, when pump activates"); -HomieSetting wateringTime0("plant0MaxPumpTime", "time seconds Pump0 is running (60 is the default)"); -HomieSetting wateringTime1("plant1MaxPumpTime", "time seconds Pump1 is running (60 is the default)"); -HomieSetting wateringTime2("plant2MaxPumpTime", "time seconds Pump2 is running (60 is the default)"); -HomieSetting wateringTime3("plant3MaxPumpTime", "time seconds Pump3 is running (60 is the default)"); -HomieSetting wateringTime4("plant4MaxPumpTime", "time seconds Pump4 is running (60 is the default)"); -HomieSetting wateringTime5("plant5MaxPumpTime", "time seconds Pump5 is running (60 is the default)"); -HomieSetting wateringTime6("plant6MaxPumpTime", "time seconds Pump6 is running (60 is the default)"); -HomieSetting wateringIdleTime0("plant0MinPumpIdle", "time in seconds Pump0 will wait (60 is the default)"); -HomieSetting wateringIdleTime1("plant1MinPumpIdle", "time in seconds Pump1 will wait (60 is the default)"); -HomieSetting wateringIdleTime2("plant2MinPumpIdle", "time in seconds Pump2 will wait (60 is the default)"); -HomieSetting wateringIdleTime3("plant3MinPumpIdle", "time in seconds Pump3 will wait (60 is the default)"); -HomieSetting wateringIdleTime4("plant4MinPumpIdle", "time in seconds Pump4 will wait (60 is the default)"); -HomieSetting wateringIdleTime5("plant5MinPumpIdle", "time in seconds Pump5 will wait (60 is the default)"); -HomieSetting wateringIdleTime6("plant6MinPumpIdle", "time in seconds Pump6 will wait (60 is the default)"); +HomieSetting waterLevelMax("watermaxlevel", "distance at maximum water level"); +HomieSetting waterLevelMin("waterminlevel", "distance at minimum water level (pumps still covered)"); +HomieSetting waterLevelWarn("waterlevelwarn", "warn if below this water level %"); +HomieSetting waterLevelVol("waterVolume", "ml between minimum and maximum"); Ds18B20 dallas(SENSOR_DS18B20); Plant mPlants[MAX_PLANTS] = { - Plant(SENSOR_PLANT0, OUTPUT_PUMP0, &plant0, &plant0SensorTrigger, &wateringTime0, &wateringIdleTime0), - Plant(SENSOR_PLANT1, OUTPUT_PUMP1, &plant1, &plant1SensorTrigger, &wateringTime1, &wateringIdleTime1), - Plant(SENSOR_PLANT2, OUTPUT_PUMP2, &plant2, &plant2SensorTrigger, &wateringTime2, &wateringIdleTime2), - Plant(SENSOR_PLANT3, OUTPUT_PUMP3, &plant3, &plant3SensorTrigger, &wateringTime3, &wateringIdleTime3), - Plant(SENSOR_PLANT4, OUTPUT_PUMP4, &plant4, &plant4SensorTrigger, &wateringTime4, &wateringIdleTime4), - Plant(SENSOR_PLANT5, OUTPUT_PUMP5, &plant5, &plant5SensorTrigger, &wateringTime5, &wateringIdleTime5), - Plant(SENSOR_PLANT6, OUTPUT_PUMP6, &plant6, &plant6SensorTrigger, &wateringTime6, &wateringIdleTime6) + Plant(SENSOR_PLANT0, OUTPUT_PUMP0, 0), + Plant(SENSOR_PLANT1, OUTPUT_PUMP1, 1), + Plant(SENSOR_PLANT2, OUTPUT_PUMP2, 2), + Plant(SENSOR_PLANT3, OUTPUT_PUMP3, 3), + Plant(SENSOR_PLANT4, OUTPUT_PUMP4, 4), + Plant(SENSOR_PLANT5, OUTPUT_PUMP5, 5), + Plant(SENSOR_PLANT6, OUTPUT_PUMP6, 6) }; void readAnalogValues() { @@ -134,8 +112,6 @@ void readAnalogValues() { */ void loopHandler() { - int waterLevelPercent = (100 * mWaterGone) / waterLevel.get(); - /* Move from Setup to this position, because the Settings are only here available */ if (!mLoopInited) { // Configure Deep Sleep: @@ -156,7 +132,7 @@ void loopHandler() { plant6.setProperty("switch").send(String("OFF")); #endif - for(int i=0; i < plantCnt.get() && i < MAX_PLANTS; i++) { + for(int i=0; i < MAX_PLANTS; i++) { mPlants[i].calculateSensorValue(AMOUNT_SENOR_QUERYS); mPlants[i].setProperty("moist").send(String(100 * mPlants[i].getSensorValue() / 4095 )); /* the last Plant, that was watered is stored in non volatile memory */ @@ -170,14 +146,14 @@ void loopHandler() { } } - sensorWater.setProperty("remaining").send(String(waterLevelPercent)); - Serial << "Water : " << mWaterGone << " cm (" << waterLevelPercent << "%)" << endl; + sensorWater.setProperty("remaining").send(String(waterLevelMax.get() - mWaterGone )); + Serial << "Water : " << mWaterGone << " cm (" << String(waterLevelMax.get() - mWaterGone ) << "%)" << endl; /* Check if a plant needs water */ if (gCurrentPlant > 0) { int plntIdx = (gCurrentPlant-1); if (mPlants[plntIdx].isPumpRequired() && - (waterLevelPercent > waterMinPercent.get()) && + (mWaterGone > waterLevelMin.get()) && (digitalRead(mPlants[plntIdx].getPumpPin()) == LOW) ) { Serial << "Plant" << plntIdx << " needs water" << endl; mPlants[plntIdx].setProperty("switch").send(String("ON")); @@ -214,7 +190,7 @@ void loopHandler() { } /* Main Loop functionality */ - if (waterLevelPercent <= waterMinPercent.get()) { + if (mWaterGone <= waterLevelMin.get()) { /* let the ESP sleep qickly, as nothing must be done */ if ((millis() >= (MIN_TIME_RUNNING * MS_TO_S)) && (deepSleepTime.get() > 0)) { mDeepSleep = true; @@ -400,37 +376,6 @@ void setup() { // Load the settings deepSleepTime.setDefaultValue(0); deepSleepNightTime.setDefaultValue(0); - wateringTime0.setDefaultValue(60); - wateringTime1.setDefaultValue(60); - wateringTime2.setDefaultValue(60); - wateringTime3.setDefaultValue(60); - wateringTime4.setDefaultValue(60); - wateringTime5.setDefaultValue(60); - wateringTime6.setDefaultValue(60); - plantCnt.setDefaultValue(0).setValidator([] (long candidate) { - return ((candidate >= 0) && (candidate <= 7) ); - }); - plant0SensorTrigger.setDefaultValue(4000); - plant1SensorTrigger.setDefaultValue(4000); - plant2SensorTrigger.setDefaultValue(4000); - plant3SensorTrigger.setDefaultValue(4000); - plant4SensorTrigger.setDefaultValue(4000); - plant5SensorTrigger.setDefaultValue(4000); - plant6SensorTrigger.setDefaultValue(4000); - wateringDeepSleep.setDefaultValue(60); - - wateringIdleTime0.setDefaultValue(60); - wateringIdleTime1.setDefaultValue(60); - wateringIdleTime2.setDefaultValue(60); - wateringIdleTime3.setDefaultValue(60); - wateringIdleTime4.setDefaultValue(60); - wateringIdleTime5.setDefaultValue(60); - wateringIdleTime6.setDefaultValue(60); - - #ifdef HC_SR04 - waterLevel.setDefaultValue(50); - waterMinPercent.setDefaultValue(5); - #endif if (mConfigured) { // Advertise topics @@ -502,7 +447,7 @@ void setup() { Homie.setup(); /* Intialize inputs and outputs */ - for(int i=0; i < plantCnt.get(); i++) { + for(int i=0; i < MAX_PLANTS; i++) { pinMode(mPlants[i].getPumpPin(), OUTPUT); pinMode(mPlants[i].getSensorPin(), ANALOG); digitalWrite(mPlants[i].getPumpPin(), LOW); @@ -528,7 +473,10 @@ void setup() { esp_sleep_enable_timer_wakeup(usSleepTime); } - if (mConfigured && (ADC_5V_TO_3V3(lipoSenor) < MINIMUM_LIPO_VOLT) && (deepSleepTime.get()) ) { + if (mConfigured && + (ADC_5V_TO_3V3(lipoSenor) < MINIMUM_LIPO_VOLT) && + (ADC_5V_TO_3V3(lipoSenor) > NO_LIPO_VOLT) && + (deepSleepTime.get()) ) { long sleepEmptyLipo = (deepSleepTime.get() * EMPTY_LIPO_MULTIPL); Serial << "HOMIE | Change sleeping to " << sleepEmptyLipo << " ms as lipo is at " << ADC_5V_TO_3V3(lipoSenor) << "V" << endl; esp_sleep_enable_timer_wakeup(sleepEmptyLipo * 1000U);