diff --git a/esp32/include/ControllerConfiguration.h b/esp32/include/ControllerConfiguration.h index c460bde..f279d09 100644 --- a/esp32/include/ControllerConfiguration.h +++ b/esp32/include/ControllerConfiguration.h @@ -69,8 +69,12 @@ #define SENSOR_TANK_ECHO GPIO_NUM_16 /**< GPIO 16 - echo feedback of water sensor */ #define SENSOR_TANK_TRG GPIO_NUM_17 /**< GPIO 17 - trigger for water sensor */ #define BUTTON GPIO_NUM_0 /**< GPIO 0 - Fix button of NodeMCU */ -#define CUSTOM1_PIN3 GPIO_NUM_2 /**< GPIO 2 - Custom GPIO controlling a MOSFET, connected to GND */ -#define CUSTOM1_PIN2 GPIO_NUM_12 /**< GPIO 4 - custom GPIO directly connected to GPIO header */ + +#define CUSTOM1_PIN1 GPIO_NUM_34 /** direct gpio */ +#define CUSTOM1_PIN3 GPIO_NUM_35 /** direct gpio */ +#define CUSTOM1_PIN5 GPIO_NUM_2 /** mosfet controlled */ +#define CUSTOM1_PIN7 GPIO_NUM_12 /** mosfet controlled */ + #define I2C1_SDA GPIO_NUM_34 /**< GPIO 34 - I2C */ #define I2C1_SCL GPIO_NUM_35 /**< GPIO 35 - I2C */ /* @} */ @@ -80,6 +84,8 @@ */ #define FIRMWARE_VERSION "sw 1.3 hw 0.10" +#define TIMED_LIGHT_PIN CUSTOM1_PIN5 + #define MOIST_SENSOR_MAX_FRQ 60000 // 60kHz (500Hz margin) #define MOIST_SENSOR_MIN_FRQ 1000 // 1kHz (500Hz margin) diff --git a/esp32/include/HomieConfiguration.h b/esp32/include/HomieConfiguration.h index 6cad4ad..5794f28 100644 --- a/esp32/include/HomieConfiguration.h +++ b/esp32/include/HomieConfiguration.h @@ -51,6 +51,11 @@ HomieNode plant4("plant4", "Plant 4", "Plant"); /**< dynamic Homie information f HomieNode plant5("plant5", "Plant 5", "Plant"); /**< dynamic Homie information for sixth plant */ HomieNode plant6("plant6", "Plant 6", "Plant"); /**< dynamic Homie information for seventh plant */ +#if defined(TIMED_LIGHT_PIN) + HomieNode timedLightNode("timedLight", "TimedLight", "Status"); +#endif // TIMED_LIGHT_PIN + + HomieNode sensorLipo("lipo", "Battery Status", "Lipo"); HomieNode sensorSolar("solar", "Solar Status", "Solarpanel"); HomieNode sensorWater("water", "WaterSensor", "Water"); @@ -78,6 +83,14 @@ HomieSetting lipoSensorAddr("lipoDSAddr", "1wire address for lipo HomieSetting waterSensorAddr("tankDSAddr", "1wire address for water temperature sensor"); HomieSetting ntpServer("ntpServer", "NTP server (pool.ntp.org as default)"); +#if defined(TIMED_LIGHT_PIN) + HomieSetting timedLightVoltageCutoff("LightVoltageCutoff", "voltage at wich to disable light"); + HomieSetting timedLightStart("LightStart", "hour to start light"); + HomieSetting timedLightEnd("LightEnd", "hour to end light"); + HomieSetting timedLightOnlyWhenDark("LightOnlyDark", "only enable light, if solar is low"); +#endif // TIMED_LIGHT_PIN + + /** * @} */ diff --git a/esp32/include/PlantCtrl.h b/esp32/include/PlantCtrl.h index 72b3078..0fda26d 100644 --- a/esp32/include/PlantCtrl.h +++ b/esp32/include/PlantCtrl.h @@ -18,7 +18,7 @@ #include "RunningMedian.h" #include "MathUtils.h" -#define MOISTURE_MEASUREMENT_DURATION 500 /** ms */ +#define MOISTURE_MEASUREMENT_DURATION 400 /** ms */ class Plant diff --git a/esp32/src/main.cpp b/esp32/src/main.cpp index 2850e1d..1dabab0 100644 --- a/esp32/src/main.cpp +++ b/esp32/src/main.cpp @@ -57,9 +57,10 @@ ******************************************************************************/ void log(int level, String message, int code); -int determineNextPump(); +int determineNextPump(bool lowLight); void plantcontrol(); void readPowerSwitchedSensors(); +bool determineTimedLightState(bool lowLight); /****************************************************************************** * NON VOLATILE VARIABLES in DEEP SLEEP @@ -67,6 +68,10 @@ void readPowerSwitchedSensors(); RTC_DATA_ATTR int lastPumpRunning = -1; /**< store last successfully waterd plant */ RTC_DATA_ATTR long lastWaterValue = 0; /**< to calculate the used water per plant */ +#if defined(TIMED_LIGHT_PIN) + RTC_DATA_ATTR bool timedLightOn = false; /**< allow fast recovery after poweron */ +#endif // TIMED_LIGHT_PIN + RTC_DATA_ATTR long rtcLastWateringPlant[MAX_PLANTS] = {0}; RTC_DATA_ATTR long consecutiveWateringPlant[MAX_PLANTS] = {0}; @@ -132,6 +137,9 @@ void espDeepSleepFor(long seconds, bool activatePump) log(LOG_LEVEL_DEBUG, "NTP timeout before deepsleep", LOG_DEBUG_CODE); } } + + //allo hold for all digital pins + gpio_deep_sleep_hold_en(); esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF); esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_ON); @@ -139,13 +147,12 @@ void espDeepSleepFor(long seconds, bool activatePump) if (activatePump) { esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_ON); - gpio_deep_sleep_hold_en(); + gpio_hold_en(OUTPUT_ENABLE_PUMP); //pump pwr } else { gpio_hold_dis(OUTPUT_ENABLE_PUMP); //pump pwr - gpio_deep_sleep_hold_dis(); digitalWrite(OUTPUT_ENABLE_PUMP, LOW); digitalWrite(OUTPUT_ENABLE_SENSOR, LOW); for (int i = 0; i < MAX_PLANTS; i++) @@ -160,7 +167,10 @@ void espDeepSleepFor(long seconds, bool activatePump) gpio_hold_en(OUTPUT_PUMP4); gpio_hold_en(OUTPUT_PUMP5); gpio_hold_en(OUTPUT_PUMP6); - //FIXME fix for outher outputs + #if defined(TIMED_LIGHT_PIN) + gpio_hold_en(TIMED_LIGHT_PIN); + #endif // TIMED_LIGHT_PIN + esp_sleep_enable_timer_wakeup((seconds * 1000U * 1000U)); if (mAliveWasRead) @@ -410,9 +420,8 @@ void onHomieEvent(const HomieEvent &event) } } -int determineNextPump() +int determineNextPump(bool isLowLight) { - bool isLowLight = (mSolarVoltage < SOLAR_CHARGE_MIN_VOLTAGE); int pumpToUse = -1; for (int i = 0; i < MAX_PLANTS; i++) { @@ -601,6 +610,13 @@ void setup() WiFi.mode(WIFI_OFF); Serial.flush(); + //restore state before releasing pin, to prevent flickering + #if defined(TIMED_LIGHT_PIN) + pinMode(TIMED_LIGHT_PIN, OUTPUT); + digitalWrite(TIMED_LIGHT_PIN, timedLightOn); + gpio_hold_dis(TIMED_LIGHT_PIN); + #endif // TIMED_LIGHT_PIN + gpio_hold_dis(OUTPUT_PUMP0); gpio_hold_dis(OUTPUT_PUMP1); gpio_hold_dis(OUTPUT_PUMP2); @@ -683,9 +699,20 @@ void setup() waterLevelVol.setDefaultValue(5000); /* 5l in ml */ lipoSensorAddr.setDefaultValue(""); waterSensorAddr.setDefaultValue(""); - pumpIneffectiveWarning.setDefaultValue(600).setValidator([](long candidate) + pumpIneffectiveWarning.setDefaultValue(5).setValidator([](long candidate) { return (candidate > 0) && (candidate < (20)); }); - pumpIneffectiveWarning.setDefaultValue(5); + + #if defined(TIMED_LIGHT_PIN) + timedLightStart.setDefaultValue(18).setValidator([](long candidate) + { return (candidate > 0) && (candidate < (25)); }); + timedLightEnd.setDefaultValue(23).setValidator([](long candidate) + { return (candidate > 0) && (candidate < (22)); }); + timedLightOnlyWhenDark.setDefaultValue(true); + timedLightVoltageCutoff.setDefaultValue(3.8).setValidator([](double candidate) + { return (candidate > 3.3) && (candidate < (4.2)); }); + #endif // TIMED_LIGHT_PIN + + Homie.setLoopFunction(homieLoop); Homie.onEvent(onHomieEvent); @@ -891,9 +918,10 @@ void plantcontrol() Serial.flush(); } + bool isLowLight = (mSolarVoltage < SOLAR_CHARGE_MIN_VOLTAGE); bool hasWater = true; //FIXMEmWaterGone > waterLevelMin.get(); //FIXME no water warning message - lastPumpRunning = determineNextPump(); + lastPumpRunning = determineNextPump(isLowLight); if (lastPumpRunning != -1 && !hasWater) { log(LOG_LEVEL_ERROR, LOG_PUMP_BUTNOTANK_MESSAGE, LOG_PUMP_BUTNOTANK_CODE); @@ -917,6 +945,13 @@ void plantcontrol() } } + #if defined(TIMED_LIGHT_PIN) + bool shouldLight = determineTimedLightState(isLowLight); + timedLightOn = shouldLight; + digitalWrite(TIMED_LIGHT_PIN, shouldLight); + #endif // TIMED_LIGHT_PIN + + /* Always handle one of the deep sleep duration */ if (lastPumpRunning == -1 || !hasWater) { @@ -939,6 +974,42 @@ void plantcontrol() /** @}*/ + +bool determineTimedLightState(bool lowLight){ + bool onlyAllowedWhenDark = timedLightOnlyWhenDark.get(); + long hoursStart = timedLightStart.get(); + long hoursEnd = timedLightEnd.get(); + + //ntp missing + if(getCurrentTime() < 10000){ + timedLightNode.setProperty("state").send(String("Off, missing ntp")); + return false; + } + if(onlyAllowedWhenDark && !lowLight){ + timedLightNode.setProperty("state").send(String("Off, not dark")); + return false; + } + + if (((hoursStart > hoursEnd) && + (getCurrentHour() >= hoursStart || getCurrentHour() <= hoursEnd)) || + /* Handle e.g. start = 8, end = 21 */ + ((hoursStart < hoursEnd) && + (getCurrentHour() >= hoursStart && getCurrentHour() <= hoursEnd))) + { + if(battery.getVoltage(BATTSENSOR_INDEX_BATTERY) >= timedLightVoltageCutoff.get() ){ + timedLightNode.setProperty("state").send(String("On")); + return true; + }else { + timedLightNode.setProperty("state").send(String("Off, due to missing voltage")); + return false; + } + + } else { + timedLightNode.setProperty("state").send(String("Off, outside worktime")); + return false; + } +} + void log(int level, String message, int statusCode) { String buffer;