wip new pump system
This commit is contained in:
		@@ -20,7 +20,6 @@
 | 
				
			|||||||
  "settings": {
 | 
					  "settings": {
 | 
				
			||||||
    "deepsleep"  : 60000,
 | 
					    "deepsleep"  : 60000,
 | 
				
			||||||
    "nightsleep" : 60000,
 | 
					    "nightsleep" : 60000,
 | 
				
			||||||
    "pumpdeepsleep": 1000,
 | 
					 | 
				
			||||||
    "watermaxlevel": 50,
 | 
					    "watermaxlevel": 50,
 | 
				
			||||||
    "watermin" : 5, 
 | 
					    "watermin" : 5, 
 | 
				
			||||||
    "plants" : 3,
 | 
					    "plants" : 3,
 | 
				
			||||||
@@ -44,6 +43,13 @@
 | 
				
			|||||||
    "plant3MinPumpIdle": 10000,
 | 
					    "plant3MinPumpIdle": 10000,
 | 
				
			||||||
    "plant4MinPumpIdle": 10000,
 | 
					    "plant4MinPumpIdle": 10000,
 | 
				
			||||||
    "plant5MinPumpIdle": 10000,
 | 
					    "plant5MinPumpIdle": 10000,
 | 
				
			||||||
    "plant6MinPumpIdle": 10000
 | 
					    "plant6MinPumpIdle": 10000,
 | 
				
			||||||
 | 
					    "plant0PumpDuration": 5,
 | 
				
			||||||
 | 
					    "plant1PumpDuration": 5,
 | 
				
			||||||
 | 
					    "plant2PumpDuration": 5,
 | 
				
			||||||
 | 
					    "plant3PumpDuration": 5,
 | 
				
			||||||
 | 
					    "plant4PumpDuration": 5,
 | 
				
			||||||
 | 
					    "plant5PumpDuration": 5,
 | 
				
			||||||
 | 
					    "plant6PumpDuration": 5
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -94,7 +94,7 @@
 | 
				
			|||||||
#define BATTSENSOR_INDEX_BATTERY    1
 | 
					#define BATTSENSOR_INDEX_BATTERY    1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MQTT_TIMEOUT                (1000 * 60) /**< After 10 seconds, MQTT is expected to be connected */
 | 
					#define MQTT_TIMEOUT                (1000 * 60) /**< After 10 seconds, MQTT is expected to be connected */
 | 
				
			||||||
#define ESP_STALE_TIMEOUT           (MQTT_TIMEOUT+(30*1000))
 | 
					#define ESP_STALE_TIMEOUT           (MQTT_TIMEOUT+(120*1000))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MAX_PLANTS          7
 | 
					#define MAX_PLANTS          7
 | 
				
			||||||
#define SOLAR_CHARGE_MIN_VOLTAGE 7  /**< Sun is rising (morning detected) */
 | 
					#define SOLAR_CHARGE_MIN_VOLTAGE 7  /**< Sun is rising (morning detected) */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -73,7 +73,6 @@ HomieNode stayAlive("stay", "alive", "alive");  /**< Necessary for Mqtt Active C
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
HomieSetting<long> deepSleepTime("sleep", "time in seconds to sleep");
 | 
					HomieSetting<long> deepSleepTime("sleep", "time in seconds to sleep");
 | 
				
			||||||
HomieSetting<long> deepSleepNightTime("nightsleep", "time in seconds to sleep (0 uses same setting: deepsleep at night, too)");
 | 
					HomieSetting<long> deepSleepNightTime("nightsleep", "time in seconds to sleep (0 uses same setting: deepsleep at night, too)");
 | 
				
			||||||
HomieSetting<long> wateringDeepSleep("pumpsleep", "time seconds to sleep, while a pump is running");
 | 
					 | 
				
			||||||
HomieSetting<long> pumpIneffectiveWarning("pumpConsecutiveWarn", "if the pump was triggered this amount directly after each cooldown, without resolving dryness, warn");
 | 
					HomieSetting<long> pumpIneffectiveWarning("pumpConsecutiveWarn", "if the pump was triggered this amount directly after each cooldown, without resolving dryness, warn");
 | 
				
			||||||
HomieSetting<long> waterLevelMax("tankmax", "distance (mm) at maximum water level");
 | 
					HomieSetting<long> waterLevelMax("tankmax", "distance (mm) at maximum water level");
 | 
				
			||||||
HomieSetting<long> waterLevelMin("tankmin", "distance (mm) at minimum water level (pumps still covered)");
 | 
					HomieSetting<long> waterLevelMin("tankmin", "distance (mm) at minimum water level (pumps still covered)");
 | 
				
			||||||
@@ -107,7 +106,8 @@ HomieSetting<const char *> ntpServer("ntpServer", "NTP server (pool.ntp.org as d
 | 
				
			|||||||
        HomieSetting<long> mPumpAllowedHourRangeEnd##plant = HomieSetting<long>("hourend" strplant, "Plant" strplant " - Range pump allowed hour end (0-23)");                                            \
 | 
					        HomieSetting<long> mPumpAllowedHourRangeEnd##plant = HomieSetting<long>("hourend" strplant, "Plant" strplant " - Range pump allowed hour end (0-23)");                                            \
 | 
				
			||||||
        HomieSetting<bool> mPumpOnlyWhenLowLight##plant = HomieSetting<bool>("lowLight" strplant, "Plant" strplant " - Enable the Pump only, when there is no sunlight"); \
 | 
					        HomieSetting<bool> mPumpOnlyWhenLowLight##plant = HomieSetting<bool>("lowLight" strplant, "Plant" strplant " - Enable the Pump only, when there is no sunlight"); \
 | 
				
			||||||
        HomieSetting<long> mPumpCooldownInHours##plant = HomieSetting<long>("delay" strplant, "Plant" strplant " - How long to wait until the pump is activated again (minutes)");                      \
 | 
					        HomieSetting<long> mPumpCooldownInHours##plant = HomieSetting<long>("delay" strplant, "Plant" strplant " - How long to wait until the pump is activated again (minutes)");                      \
 | 
				
			||||||
        PlantSettings_t mSetting##plant = {&mSensorDry##plant, &mPumpAllowedHourRangeStart##plant, &mPumpAllowedHourRangeEnd##plant, &mPumpOnlyWhenLowLight##plant, &mPumpCooldownInHours##plant}; \
 | 
					        HomieSetting<long> pPumpDuration##plant = HomieSetting<long>("pumpDuration" strplant, "Plant" strplant " - time seconds or ml (if using flowmeter) to water when pump is active");                      \
 | 
				
			||||||
 | 
					        PlantSettings_t mSetting##plant = {&mSensorDry##plant, &mPumpAllowedHourRangeStart##plant, &mPumpAllowedHourRangeEnd##plant, &mPumpOnlyWhenLowLight##plant, &mPumpCooldownInHours##plant, &pPumpDuration##plant}; \
 | 
				
			||||||
        /**< Generate all settings for one plant \
 | 
					        /**< Generate all settings for one plant \
 | 
				
			||||||
         * \
 | 
					         * \
 | 
				
			||||||
         * Feature to start pumping only at morning: @link{SOLAR_CHARGE_MIN_VOLTAGE} and @link{SOLAR_CHARGE_MAX_VOLTAGE} \
 | 
					         * Feature to start pumping only at morning: @link{SOLAR_CHARGE_MIN_VOLTAGE} and @link{SOLAR_CHARGE_MAX_VOLTAGE} \
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,6 +23,7 @@ typedef struct PlantSettings_t
 | 
				
			|||||||
    HomieSetting<long> *pPumpAllowedHourRangeEnd;
 | 
					    HomieSetting<long> *pPumpAllowedHourRangeEnd;
 | 
				
			||||||
    HomieSetting<bool> *pPumpOnlyWhenLowLight;
 | 
					    HomieSetting<bool> *pPumpOnlyWhenLowLight;
 | 
				
			||||||
    HomieSetting<long> *pPumpCooldownInHours;
 | 
					    HomieSetting<long> *pPumpCooldownInHours;
 | 
				
			||||||
 | 
					    HomieSetting<long> *pPumpDuration;
 | 
				
			||||||
} PlantSettings_t;
 | 
					} PlantSettings_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
@@ -141,6 +141,10 @@ public:
 | 
				
			|||||||
    bool switchHandler(const HomieRange& range, const String& value);
 | 
					    bool switchHandler(const HomieRange& range, const String& value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void setSwitchHandler(HomieInternals::PropertyInputHandler f);
 | 
					    void setSwitchHandler(HomieInternals::PropertyInputHandler f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    long getPumpDuration() {
 | 
				
			||||||
 | 
					        return this->mSetting->pPumpDuration->get();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -51,6 +51,12 @@ void Plant::init(void)
 | 
				
			|||||||
        return ((candidate >= 0) && (candidate <= 1024));
 | 
					        return ((candidate >= 0) && (candidate <= 1024));
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this->mSetting->pPumpDuration->setDefaultValue(5);
 | 
				
			||||||
 | 
					        this->mSetting->pPumpDuration->setValidator([](long candidate) {
 | 
				
			||||||
 | 
					        return ((candidate >= 0) && (candidate <= 1000));
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Initialize Hardware */
 | 
					    /* Initialize Hardware */
 | 
				
			||||||
    Serial.println("Set GPIO mode " + String(mPinPump) + "=" + String(OUTPUT));
 | 
					    Serial.println("Set GPIO mode " + String(mPinPump) + "=" + String(OUTPUT));
 | 
				
			||||||
    Serial.flush();
 | 
					    Serial.flush();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -66,13 +66,11 @@ bool determineTimedLightState(bool lowLight);
 | 
				
			|||||||
 *                       NON VOLATILE VARIABLES in DEEP SLEEP
 | 
					 *                       NON VOLATILE VARIABLES in DEEP SLEEP
 | 
				
			||||||
******************************************************************************/
 | 
					******************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RTC_DATA_ATTR int lastPumpRunning = -1; /**< store last successfully waterd plant */
 | 
					RTC_DATA_ATTR long lastWaterValue = 0; /**< to calculate the used water per plant */
 | 
				
			||||||
RTC_DATA_ATTR long lastWaterValue = 0;  /**< to calculate the used water per plant */
 | 
					 | 
				
			||||||
#if defined(TIMED_LIGHT_PIN)
 | 
					#if defined(TIMED_LIGHT_PIN)
 | 
				
			||||||
  RTC_DATA_ATTR bool timedLightOn = false; /**< allow fast recovery after poweron */
 | 
					RTC_DATA_ATTR bool timedLightOn = false;                  /**< allow fast recovery after poweron */
 | 
				
			||||||
  RTC_DATA_ATTR bool timedLightLowVoltageTriggered = false; /**remember if it was shut down due to voltage level */
 | 
					RTC_DATA_ATTR bool timedLightLowVoltageTriggered = false; /**remember if it was shut down due to voltage level */
 | 
				
			||||||
#endif // TIMED_LIGHT_PIN
 | 
					#endif                                                    // TIMED_LIGHT_PIN
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
RTC_DATA_ATTR long rtcLastWateringPlant[MAX_PLANTS] = {0};
 | 
					RTC_DATA_ATTR long rtcLastWateringPlant[MAX_PLANTS] = {0};
 | 
				
			||||||
RTC_DATA_ATTR long consecutiveWateringPlant[MAX_PLANTS] = {0};
 | 
					RTC_DATA_ATTR long consecutiveWateringPlant[MAX_PLANTS] = {0};
 | 
				
			||||||
@@ -84,6 +82,7 @@ bool volatile mDownloadMode = false; /**< Controller must not sleep */
 | 
				
			|||||||
bool volatile mSensorsRead = false;  /**< Sensors are read without Wifi or MQTT */
 | 
					bool volatile mSensorsRead = false;  /**< Sensors are read without Wifi or MQTT */
 | 
				
			||||||
bool volatile mAliveWasRead = false;
 | 
					bool volatile mAliveWasRead = false;
 | 
				
			||||||
bool volatile mMQTTReady = false;
 | 
					bool volatile mMQTTReady = false;
 | 
				
			||||||
 | 
					int volatile pumpToRun = -1; /** pump to run  at the end of the cycle */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool mConfigured = false;
 | 
					bool mConfigured = false;
 | 
				
			||||||
long nextBlink = 0; /**< Time needed in main loop to support expected blink code */
 | 
					long nextBlink = 0; /**< Time needed in main loop to support expected blink code */
 | 
				
			||||||
@@ -112,7 +111,7 @@ Plant mPlants[MAX_PLANTS] = {
 | 
				
			|||||||
 *                            LOCAL FUNCTIONS
 | 
					 *                            LOCAL FUNCTIONS
 | 
				
			||||||
******************************************************************************/
 | 
					******************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void espDeepSleepFor(long seconds, bool activatePump)
 | 
					void espDeepSleep()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  if (mDownloadMode)
 | 
					  if (mDownloadMode)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
@@ -145,35 +144,26 @@ void espDeepSleepFor(long seconds, bool activatePump)
 | 
				
			|||||||
  esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF);
 | 
					  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);
 | 
					  esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_ON);
 | 
				
			||||||
  esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_FAST_MEM, ESP_PD_OPTION_ON);
 | 
					  esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_FAST_MEM, ESP_PD_OPTION_ON);
 | 
				
			||||||
  if (activatePump)
 | 
					  esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_ON);
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_ON);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    gpio_hold_en(OUTPUT_ENABLE_PUMP); //pump pwr
 | 
					#if defined(TIMED_LIGHT_PIN)
 | 
				
			||||||
 | 
					  gpio_hold_en(TIMED_LIGHT_PIN);
 | 
				
			||||||
 | 
					#endif // TIMED_LIGHT_PIN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  long secondsToSleep = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (mSolarVoltage < SOLAR_CHARGE_MIN_VOLTAGE)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    log(LOG_LEVEL_INFO, String(String(mSolarVoltage) + "V! No pumps to activate and low light, deepSleepNight"), LOG_NOPUMP_LOWLIGHT);
 | 
				
			||||||
 | 
					    secondsToSleep = deepSleepTime.get();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  else
 | 
					  else
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    gpio_hold_dis(OUTPUT_ENABLE_PUMP); //pump pwr
 | 
					    log(LOG_LEVEL_INFO, "No pumps to activate, deepSleep", LOG_NOPUMPS);
 | 
				
			||||||
    digitalWrite(OUTPUT_ENABLE_PUMP, LOW);
 | 
					    secondsToSleep = deepSleepTime.get();
 | 
				
			||||||
    digitalWrite(OUTPUT_ENABLE_SENSOR, LOW);
 | 
					 | 
				
			||||||
    for (int i = 0; i < MAX_PLANTS; i++)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      mPlants[i].deactivatePump();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  gpio_hold_en(OUTPUT_PUMP0);
 | 
					 | 
				
			||||||
  gpio_hold_en(OUTPUT_PUMP1);
 | 
					 | 
				
			||||||
  gpio_hold_en(OUTPUT_PUMP2);
 | 
					 | 
				
			||||||
  gpio_hold_en(OUTPUT_PUMP3);
 | 
					 | 
				
			||||||
  gpio_hold_en(OUTPUT_PUMP4);
 | 
					 | 
				
			||||||
  gpio_hold_en(OUTPUT_PUMP5);
 | 
					 | 
				
			||||||
  gpio_hold_en(OUTPUT_PUMP6);
 | 
					 | 
				
			||||||
  #if defined(TIMED_LIGHT_PIN)
 | 
					 | 
				
			||||||
    gpio_hold_en(TIMED_LIGHT_PIN);
 | 
					 | 
				
			||||||
  #endif // TIMED_LIGHT_PIN
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  esp_sleep_enable_timer_wakeup((secondsToSleep * 1000U * 1000U));
 | 
				
			||||||
  esp_sleep_enable_timer_wakeup((seconds * 1000U * 1000U));
 | 
					 | 
				
			||||||
  if (mAliveWasRead)
 | 
					  if (mAliveWasRead)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    delay(1000);
 | 
					    delay(1000);
 | 
				
			||||||
@@ -384,7 +374,7 @@ void onHomieEvent(const HomieEvent &event)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    mSensorsRead = true; // MQTT is working, deactivate timeout logic
 | 
					    mSensorsRead = true; // MQTT is working, deactivate timeout logic
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    configTime(0, 0, ntpServer.get());
 | 
					    configTime(3600, 3600, ntpServer.get());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      getTopic(TEST_TOPIC, testopic)
 | 
					      getTopic(TEST_TOPIC, testopic)
 | 
				
			||||||
@@ -596,6 +586,61 @@ bool switch7(const HomieRange &range, const String &value)
 | 
				
			|||||||
  return mPlants[6].switchHandler(range, value);
 | 
					  return mPlants[6].switchHandler(range, value);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool pumpStarted = false;
 | 
				
			||||||
 | 
					long pumpTarget = -1;
 | 
				
			||||||
 | 
					#ifdef FLOWMETER
 | 
				
			||||||
 | 
					long pumpTargetMl = -1;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pumpActiveLoop()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!pumpStarted)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    //enable power
 | 
				
			||||||
 | 
					    WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
 | 
				
			||||||
 | 
					    digitalWrite(OUTPUT_ENABLE_PUMP, HIGH);
 | 
				
			||||||
 | 
					    delay(100);
 | 
				
			||||||
 | 
					    WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mPlants[pumpToRun].activatePump();
 | 
				
			||||||
 | 
					    //set targets
 | 
				
			||||||
 | 
					    pumpTarget = millis() + (mPlants[pumpToRun].getPumpDuration() * 1000);
 | 
				
			||||||
 | 
					#ifdef FLOWMETER
 | 
				
			||||||
 | 
					    pumpTargetMl = mPlants[pumpToRun].getPumpDuration();
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    pumpStarted = true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool targetReached = false;
 | 
				
			||||||
 | 
					#ifdef FLOWMETER
 | 
				
			||||||
 | 
					  long pumped = //readFlowMeterCounter * ratio;
 | 
				
			||||||
 | 
					  if(pumped >= pumpTargetMl))
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    targetReached = true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  mPlants[pumpToRun].setProperty("waterusage").send(String(pumped));
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (millis() > pumpTarget)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    targetReached = true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (targetReached)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    //disable all
 | 
				
			||||||
 | 
					    digitalWrite(OUTPUT_ENABLE_PUMP, LOW);
 | 
				
			||||||
 | 
					    for (int i = 0; i < MAX_PLANTS; i++)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      mPlants[i].deactivatePump();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    //disable loop, to prevent multi processing
 | 
				
			||||||
 | 
					    pumpStarted = false;
 | 
				
			||||||
 | 
					    espDeepSleep();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @brief Startup function
 | 
					 * @brief Startup function
 | 
				
			||||||
 * Is called once, the controller is started
 | 
					 * Is called once, the controller is started
 | 
				
			||||||
@@ -611,21 +656,12 @@ void setup()
 | 
				
			|||||||
  WiFi.mode(WIFI_OFF);
 | 
					  WiFi.mode(WIFI_OFF);
 | 
				
			||||||
  Serial.flush();
 | 
					  Serial.flush();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  //restore state before releasing pin, to prevent flickering
 | 
					//restore state before releasing pin, to prevent flickering
 | 
				
			||||||
  #if defined(TIMED_LIGHT_PIN)
 | 
					#if defined(TIMED_LIGHT_PIN)
 | 
				
			||||||
    pinMode(TIMED_LIGHT_PIN, OUTPUT);
 | 
					  pinMode(TIMED_LIGHT_PIN, OUTPUT);
 | 
				
			||||||
    digitalWrite(TIMED_LIGHT_PIN, timedLightOn);
 | 
					  digitalWrite(TIMED_LIGHT_PIN, timedLightOn);
 | 
				
			||||||
    gpio_hold_dis(TIMED_LIGHT_PIN);
 | 
					  gpio_hold_dis(TIMED_LIGHT_PIN);
 | 
				
			||||||
  #endif // TIMED_LIGHT_PIN
 | 
					#endif // TIMED_LIGHT_PIN
 | 
				
			||||||
 | 
					 | 
				
			||||||
  gpio_hold_dis(OUTPUT_PUMP0);
 | 
					 | 
				
			||||||
  gpio_hold_dis(OUTPUT_PUMP1);
 | 
					 | 
				
			||||||
  gpio_hold_dis(OUTPUT_PUMP2);
 | 
					 | 
				
			||||||
  gpio_hold_dis(OUTPUT_PUMP3);
 | 
					 | 
				
			||||||
  gpio_hold_dis(OUTPUT_PUMP4);
 | 
					 | 
				
			||||||
  gpio_hold_dis(OUTPUT_PUMP5);
 | 
					 | 
				
			||||||
  gpio_hold_dis(OUTPUT_PUMP6);
 | 
					 | 
				
			||||||
  gpio_hold_dis(OUTPUT_ENABLE_PUMP);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* Intialize Plant */
 | 
					  /* Intialize Plant */
 | 
				
			||||||
  for (int i = 0; i < MAX_PLANTS; i++)
 | 
					  for (int i = 0; i < MAX_PLANTS; i++)
 | 
				
			||||||
@@ -691,7 +727,6 @@ void setup()
 | 
				
			|||||||
  deepSleepTime.setDefaultValue(600).setValidator([](long candidate)
 | 
					  deepSleepTime.setDefaultValue(600).setValidator([](long candidate)
 | 
				
			||||||
                                                  { return (candidate > 0) && (candidate < (60 * 60 * 2) /** 2h max sleep */); });
 | 
					                                                  { return (candidate > 0) && (candidate < (60 * 60 * 2) /** 2h max sleep */); });
 | 
				
			||||||
  deepSleepNightTime.setDefaultValue(600);
 | 
					  deepSleepNightTime.setDefaultValue(600);
 | 
				
			||||||
  wateringDeepSleep.setDefaultValue(5);
 | 
					 | 
				
			||||||
  ntpServer.setDefaultValue("pool.ntp.org");
 | 
					  ntpServer.setDefaultValue("pool.ntp.org");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* waterLevelMax 1000    */          /* 100cm in mm */
 | 
					  /* waterLevelMax 1000    */          /* 100cm in mm */
 | 
				
			||||||
@@ -701,18 +736,17 @@ void setup()
 | 
				
			|||||||
  lipoSensorAddr.setDefaultValue("");
 | 
					  lipoSensorAddr.setDefaultValue("");
 | 
				
			||||||
  waterSensorAddr.setDefaultValue("");
 | 
					  waterSensorAddr.setDefaultValue("");
 | 
				
			||||||
  pumpIneffectiveWarning.setDefaultValue(5).setValidator([](long candidate)
 | 
					  pumpIneffectiveWarning.setDefaultValue(5).setValidator([](long candidate)
 | 
				
			||||||
                                                           { return (candidate > 0) && (candidate < (20)); });
 | 
					                                                         { return (candidate > 0) && (candidate < (20)); });
 | 
				
			||||||
 | 
					 | 
				
			||||||
  #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 < (24)); });
 | 
					 | 
				
			||||||
    timedLightOnlyWhenDark.setDefaultValue(true);
 | 
					 | 
				
			||||||
    timedLightVoltageCutoff.setDefaultValue(3.8).setValidator([](double candidate)
 | 
					 | 
				
			||||||
                                                           { return (candidate > 3.3) && (candidate < (4.2)); });
 | 
					 | 
				
			||||||
  #endif // TIMED_LIGHT_PIN
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#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 < (24)); });
 | 
				
			||||||
 | 
					  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.setLoopFunction(homieLoop);
 | 
				
			||||||
  Homie.onEvent(onHomieEvent);
 | 
					  Homie.onEvent(onHomieEvent);
 | 
				
			||||||
@@ -779,7 +813,7 @@ void setup()
 | 
				
			|||||||
      if (restoredConfig)
 | 
					      if (restoredConfig)
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        deleteFile(CONFIG_FILE_BACKUP);
 | 
					        deleteFile(CONFIG_FILE_BACKUP);
 | 
				
			||||||
        espDeepSleepFor(1, false);
 | 
					        espDeepSleep();
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -797,6 +831,28 @@ void setup()
 | 
				
			|||||||
  setupFinishedTimestamp = millis();
 | 
					  setupFinishedTimestamp = millis();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void selfTest()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  if (pumpToRun >= 0 && pumpToRun < MAX_PLANTS)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    mPlants[pumpToRun].deactivatePump();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (pumpToRun >= MAX_PLANTS)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    digitalWrite(OUTPUT_ENABLE_PUMP, LOW);
 | 
				
			||||||
 | 
					    nextBlink = millis() + 500;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    pumpToRun++;
 | 
				
			||||||
 | 
					    nextBlink = millis() + 5000;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (pumpToRun < MAX_PLANTS)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    mPlants[pumpToRun].activatePump();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @brief Cyclic call
 | 
					 * @brief Cyclic call
 | 
				
			||||||
 * Executs the Homie base functionallity or triggers sleeping, if requested.
 | 
					 * Executs the Homie base functionallity or triggers sleeping, if requested.
 | 
				
			||||||
@@ -816,24 +872,7 @@ void loop()
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
      else
 | 
					      else
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        if (lastPumpRunning >= 0 && lastPumpRunning < MAX_PLANTS)
 | 
					        selfTest();
 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          mPlants[lastPumpRunning].deactivatePump();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (lastPumpRunning >= MAX_PLANTS)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          digitalWrite(OUTPUT_ENABLE_PUMP, LOW);
 | 
					 | 
				
			||||||
          nextBlink = millis() + 500;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          lastPumpRunning++;
 | 
					 | 
				
			||||||
          nextBlink = millis() + 5000;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (lastPumpRunning < MAX_PLANTS)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          mPlants[lastPumpRunning].activatePump();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -858,6 +897,11 @@ void loop()
 | 
				
			|||||||
    Serial.flush();
 | 
					    Serial.flush();
 | 
				
			||||||
    esp_restart();
 | 
					    esp_restart();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (pumpToRun != -1)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    pumpActiveLoop();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/***
 | 
					/***
 | 
				
			||||||
@@ -866,14 +910,6 @@ void loop()
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
void plantcontrol()
 | 
					void plantcontrol()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  if (lastPumpRunning != -1)
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    long waterDiff = waterRawSensor.getAverage() - lastWaterValue;
 | 
					 | 
				
			||||||
    mPlants[lastPumpRunning].setProperty("waterusage").send(String(waterDiff));
 | 
					 | 
				
			||||||
    /* TODO convert diff into volume (milli liter) */
 | 
					 | 
				
			||||||
    Serial << "Plant" << lastPumpRunning << ": Water diff " << waterDiff << " mm" << endl;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (mAliveWasRead)
 | 
					  if (mAliveWasRead)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    for (int i = 0; i < MAX_PLANTS; i++)
 | 
					    for (int i = 0; i < MAX_PLANTS; i++)
 | 
				
			||||||
@@ -922,95 +958,82 @@ void plantcontrol()
 | 
				
			|||||||
  bool isLowLight = (mSolarVoltage < SOLAR_CHARGE_MIN_VOLTAGE);
 | 
					  bool isLowLight = (mSolarVoltage < SOLAR_CHARGE_MIN_VOLTAGE);
 | 
				
			||||||
  bool hasWater = true; //FIXMEmWaterGone > waterLevelMin.get();
 | 
					  bool hasWater = true; //FIXMEmWaterGone > waterLevelMin.get();
 | 
				
			||||||
  //FIXME no water warning message
 | 
					  //FIXME no water warning message
 | 
				
			||||||
  lastPumpRunning = determineNextPump(isLowLight);
 | 
					  pumpToRun = determineNextPump(isLowLight);
 | 
				
			||||||
  if (lastPumpRunning != -1 && !hasWater)
 | 
					  //early aborts
 | 
				
			||||||
 | 
					  if (pumpToRun != -1)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    log(LOG_LEVEL_ERROR, LOG_PUMP_BUTNOTANK_MESSAGE, LOG_PUMP_BUTNOTANK_CODE);
 | 
					    if (hasWater)
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  else if (lastPumpRunning != -1 && hasWater)
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    if (mDownloadMode)
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      log(LOG_LEVEL_INFO, LOG_PUMP_AND_DOWNLOADMODE, LOG_PUMP_AND_DOWNLOADMODE_CODE);
 | 
					      if (mDownloadMode)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        log(LOG_LEVEL_INFO, LOG_PUMP_AND_DOWNLOADMODE, LOG_PUMP_AND_DOWNLOADMODE_CODE);
 | 
				
			||||||
 | 
					        pumpToRun = -1;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      //prevent BOD to be paranoid
 | 
					      log(LOG_LEVEL_ERROR, LOG_PUMP_BUTNOTANK_MESSAGE, LOG_PUMP_BUTNOTANK_CODE);
 | 
				
			||||||
      WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
 | 
					      pumpToRun = -1;
 | 
				
			||||||
      digitalWrite(OUTPUT_ENABLE_PUMP, HIGH);
 | 
					 | 
				
			||||||
      delay(100);
 | 
					 | 
				
			||||||
      WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      rtcLastWateringPlant[lastPumpRunning] = getCurrentTime();
 | 
					 | 
				
			||||||
      mPlants[lastPumpRunning].activatePump();
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  #if defined(TIMED_LIGHT_PIN)
 | 
					  // go directly to sleep, skipping the pump loop
 | 
				
			||||||
    bool shouldLight = determineTimedLightState(isLowLight);
 | 
					  if (pumpToRun == -1)
 | 
				
			||||||
    timedLightOn = shouldLight;
 | 
					 | 
				
			||||||
    digitalWrite(TIMED_LIGHT_PIN, shouldLight);
 | 
					 | 
				
			||||||
  #endif // TIMED_LIGHT_PIN
 | 
					 | 
				
			||||||
  
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /* Always handle one of the deep sleep duration */
 | 
					 | 
				
			||||||
  if (lastPumpRunning == -1 || !hasWater)
 | 
					 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    if (mSolarVoltage < SOLAR_CHARGE_MIN_VOLTAGE)
 | 
					    espDeepSleep();
 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      log(LOG_LEVEL_INFO, String(String(mSolarVoltage) + "V! No pumps to activate and low light, deepSleepNight"), LOG_NOPUMP_LOWLIGHT);
 | 
					 | 
				
			||||||
      espDeepSleepFor(deepSleepNightTime.get(), false);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      log(LOG_LEVEL_INFO, "No pumps to activate, deepSleep", LOG_NOPUMPS);
 | 
					 | 
				
			||||||
      espDeepSleepFor(deepSleepTime.get(), false);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  else
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    espDeepSleepFor(wateringDeepSleep.get(), true);
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(TIMED_LIGHT_PIN)
 | 
				
			||||||
 | 
					  bool shouldLight = determineTimedLightState(isLowLight);
 | 
				
			||||||
 | 
					  timedLightOn = shouldLight;
 | 
				
			||||||
 | 
					  digitalWrite(TIMED_LIGHT_PIN, shouldLight);
 | 
				
			||||||
 | 
					#endif // TIMED_LIGHT_PIN
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** @}*/
 | 
					/** @}*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool determineTimedLightState(bool lowLight)
 | 
				
			||||||
bool determineTimedLightState(bool lowLight){
 | 
					{
 | 
				
			||||||
  bool onlyAllowedWhenDark = timedLightOnlyWhenDark.get();
 | 
					  bool onlyAllowedWhenDark = timedLightOnlyWhenDark.get();
 | 
				
			||||||
  long hoursStart = timedLightStart.get();
 | 
					  long hoursStart = timedLightStart.get();
 | 
				
			||||||
  long hoursEnd = timedLightEnd.get();
 | 
					  long hoursEnd = timedLightEnd.get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  //ntp missing
 | 
					  //ntp missing
 | 
				
			||||||
  if(getCurrentTime() < 10000){
 | 
					  if (getCurrentTime() < 10000)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    timedLightNode.setProperty("state").send(String("Off, missing ntp"));
 | 
					    timedLightNode.setProperty("state").send(String("Off, missing ntp"));
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if(onlyAllowedWhenDark && !lowLight){
 | 
					  if (onlyAllowedWhenDark && !lowLight)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    timedLightNode.setProperty("state").send(String("Off, not dark"));
 | 
					    timedLightNode.setProperty("state").send(String("Off, not dark"));
 | 
				
			||||||
    timedLightLowVoltageTriggered = false;
 | 
					    timedLightLowVoltageTriggered = false;
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (((hoursStart > hoursEnd) &&
 | 
					  if (((hoursStart > hoursEnd) &&
 | 
				
			||||||
           (getCurrentHour() >= hoursStart || getCurrentHour() <= hoursEnd)) ||
 | 
					       (getCurrentHour() >= hoursStart || getCurrentHour() <= hoursEnd)) ||
 | 
				
			||||||
          /* Handle e.g. start = 8, end = 21 */
 | 
					      /* Handle e.g. start = 8, end = 21 */
 | 
				
			||||||
          ((hoursStart < hoursEnd) &&
 | 
					      ((hoursStart < hoursEnd) &&
 | 
				
			||||||
           (getCurrentHour() >= hoursStart && getCurrentHour() <= hoursEnd)))
 | 
					       (getCurrentHour() >= hoursStart && getCurrentHour() <= hoursEnd)))
 | 
				
			||||||
      {
 | 
					  {
 | 
				
			||||||
        if(!timedLightLowVoltageTriggered && battery.getVoltage(BATTSENSOR_INDEX_BATTERY) >= timedLightVoltageCutoff.get() ){
 | 
					    if (!timedLightLowVoltageTriggered && battery.getVoltage(BATTSENSOR_INDEX_BATTERY) >= timedLightVoltageCutoff.get())
 | 
				
			||||||
          timedLightNode.setProperty("state").send(String("On"));
 | 
					    {
 | 
				
			||||||
          return true;
 | 
					      timedLightNode.setProperty("state").send(String("On"));
 | 
				
			||||||
        }else {
 | 
					      return true;
 | 
				
			||||||
          timedLightNode.setProperty("state").send(String("Off, due to missing voltage"));
 | 
					    }
 | 
				
			||||||
          timedLightLowVoltageTriggered = true;
 | 
					    else
 | 
				
			||||||
          return false;
 | 
					    {
 | 
				
			||||||
        }
 | 
					      timedLightNode.setProperty("state").send(String("Off, due to missing voltage"));
 | 
				
			||||||
 | 
					      timedLightLowVoltageTriggered = true;
 | 
				
			||||||
      } else {
 | 
					      return false;
 | 
				
			||||||
        timedLightNode.setProperty("state").send(String("Off, outside worktime"));
 | 
					    }
 | 
				
			||||||
        return false;
 | 
					  }
 | 
				
			||||||
      }
 | 
					  else
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    timedLightNode.setProperty("state").send(String("Off, outside worktime"));
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void log(int level, String message, int statusCode)
 | 
					void log(int level, String message, int statusCode)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user