diff --git a/esp32/src/main.cpp b/esp32/src/main.cpp index f52538a..527fcdd 100644 --- a/esp32/src/main.cpp +++ b/esp32/src/main.cpp @@ -21,37 +21,37 @@ const unsigned long TEMPREADCYCLE = 30000; /**< Check temperature all half minutes */ -#define AMOUNT_SENOR_QUERYS 8 -#define SENSOR_QUERY_SHIFTS 3 -#define SOLAR4SENSORS 6.0f -#define TEMP_INIT_VALUE -999.0f -#define TEMP_MAX_VALUE 85.0f +#define AMOUNT_SENOR_QUERYS 8 +#define SENSOR_QUERY_SHIFTS 3 +#define SOLAR4SENSORS 6.0f +#define TEMP_INIT_VALUE -999.0f +#define TEMP_MAX_VALUE 85.0f /********************* non volatile enable after deepsleep *******************************/ RTC_DATA_ATTR long gotoMode2AfterThisTimestamp = 0; -RTC_DATA_ATTR long rtcDeepSleepTime = 0; /**< Time, when the microcontroller shall be up again */ +RTC_DATA_ATTR long rtcDeepSleepTime = 0; /**< Time, when the microcontroller shall be up again */ RTC_DATA_ATTR long rtcLastActive0 = 0; -RTC_DATA_ATTR long rtcMoistureTrigger0 = 0; /** TEMP_INIT_VALUE) && (pFloat[0] < TEMP_MAX_VALUE) ) { - sensorTemp.setProperty("control").send( String(pFloat[0])); - } - } else if (devices >= 2) { - if ((pFloat[0] > TEMP_INIT_VALUE) && (pFloat[0] < TEMP_MAX_VALUE) ) { - sensorTemp.setProperty("temp").send( String(pFloat[0])); + if (devices < 2) + { + if ((pFloat[0] > TEMP_INIT_VALUE) && (pFloat[0] < TEMP_MAX_VALUE)) + { + sensorTemp.setProperty("control").send(String(pFloat[0])); } - if ((pFloat[1] > TEMP_INIT_VALUE) && (pFloat[1] < TEMP_MAX_VALUE) ) { - sensorTemp.setProperty("control").send( String(pFloat[1])); + } + else if (devices >= 2) + { + if ((pFloat[0] > TEMP_INIT_VALUE) && (pFloat[0] < TEMP_MAX_VALUE)) + { + sensorTemp.setProperty("temp").send(String(pFloat[0])); + } + if ((pFloat[1] > TEMP_INIT_VALUE) && (pFloat[1] < TEMP_MAX_VALUE)) + { + sensorTemp.setProperty("control").send(String(pFloat[1])); } } bool lipoTempWarning = abs(temp[0] - temp[1]) > 5; - if(lipoTempWarning){ + if (lipoTempWarning) + { Serial.println("Lipo temp incorrect, panic mode deepsleep"); espDeepSleepFor(PANIK_MODE_DEEPSLEEP); return; } - bool hasWater = true;//FIXMEmWaterGone > waterLevelMin.get(); + bool hasWater = true; //FIXMEmWaterGone > waterLevelMin.get(); //FIXME no water warning message lastPumpRunning = determineNextPump(); - if(lastPumpRunning != -1 && !hasWater){ + if (lastPumpRunning != -1 && !hasWater) + { Serial.println("Want to pump but no water"); } - if(lastPumpRunning != -1 && hasWater){ + if (lastPumpRunning != -1 && hasWater) + { digitalWrite(OUTPUT_PUMP, HIGH); setLastActivationForPump(lastPumpRunning, getCurrentTime()); mPlants[lastPumpRunning].activatePump(); } - if(lastPumpRunning == -1 || !hasWater){ - if(getSolarVoltage() < SOLAR_CHARGE_MIN_VOLTAGE){ - gotoMode2AfterThisTimestamp = getCurrentTime()+deepSleepNightTime.get(); + if (lastPumpRunning == -1 || !hasWater) + { + if (getSolarVoltage() < SOLAR_CHARGE_MIN_VOLTAGE) + { + gotoMode2AfterThisTimestamp = getCurrentTime() + deepSleepNightTime.get(); Serial.println("No pumps to activate and low light, deepSleepNight"); espDeepSleepFor(deepSleepNightTime.get()); - }else { - gotoMode2AfterThisTimestamp = getCurrentTime()+deepSleepTime.get(); + } + else + { + gotoMode2AfterThisTimestamp = getCurrentTime() + deepSleepTime.get(); Serial.println("No pumps to activate, deepSleep"); espDeepSleepFor(deepSleepTime.get()); } - - }else { + } + else + { gotoMode2AfterThisTimestamp = 0; Serial.println("Running pump, watering deepsleep"); espDeepSleepFor(wateringDeepSleep.get(), true); } - } -void setMoistureTrigger(int plantId, long value){ - if(plantId == 0){ +void setMoistureTrigger(int plantId, long value) +{ + if (plantId == 0) + { rtcMoistureTrigger0 = value; } - if(plantId == 1){ + if (plantId == 1) + { rtcMoistureTrigger1 = value; } - if(plantId == 2){ + if (plantId == 2) + { rtcMoistureTrigger2 = value; } - if(plantId == 3){ + if (plantId == 3) + { rtcMoistureTrigger3 = value; } - if(plantId == 4){ + if (plantId == 4) + { rtcMoistureTrigger4 = value; } - if(plantId == 5){ + if (plantId == 5) + { rtcMoistureTrigger5 = value; } - if(plantId == 6){ + if (plantId == 6) + { rtcMoistureTrigger6 = value; - } + } } -void setLastActivationForPump(int plantId, long value){ - if(plantId == 0){ +void setLastActivationForPump(int plantId, long value) +{ + if (plantId == 0) + { rtcLastActive0 = value; } - if(plantId == 1){ + if (plantId == 1) + { rtcLastActive1 = value; } - if(plantId == 2){ + if (plantId == 2) + { rtcLastActive2 = value; } - if(plantId == 3){ + if (plantId == 3) + { rtcLastActive3 = value; } - if(plantId == 4){ + if (plantId == 4) + { rtcLastActive4 = value; } - if(plantId == 5){ + if (plantId == 5) + { rtcLastActive5 = value; } - if(plantId == 6){ + if (plantId == 6) + { rtcLastActive6 = value; - } + } } -long getLastActivationForPump(int plantId){ - if(plantId == 0){ +long getLastActivationForPump(int plantId) +{ + if (plantId == 0) + { return rtcLastActive0; } - if(plantId == 1){ + if (plantId == 1) + { return rtcLastActive1; } - if(plantId == 2){ + if (plantId == 2) + { return rtcLastActive2; } - if(plantId == 3){ + if (plantId == 3) + { return rtcLastActive3; } - if(plantId == 4){ + if (plantId == 4) + { return rtcLastActive4; } - if(plantId == 5){ + if (plantId == 5) + { return rtcLastActive5; } - if(plantId == 6){ + if (plantId == 6) + { return rtcLastActive6; } return -1; @@ -312,7 +358,8 @@ long getLastActivationForPump(int plantId){ * @brief Sensors, that are connected to GPIOs, mandatory for WIFI. * These sensors (ADC2) can only be read when no Wifi is used. */ -void readSensors() { +void readSensors() +{ Serial << "Read Sensors" << endl; readSystemSensors(); @@ -323,8 +370,10 @@ void readSensors() { delay(100); /* wait before reading something */ - for (int readCnt=0;readCnt < AMOUNT_SENOR_QUERYS; readCnt++) { - for(int i=0; i < MAX_PLANTS; i++) { + for (int readCnt = 0; readCnt < AMOUNT_SENOR_QUERYS; readCnt++) + { + for (int i = 0; i < MAX_PLANTS; i++) + { mPlants[i].addSenseValue(); } } @@ -334,16 +383,18 @@ void readSensors() { Serial << "DS18B20" << String(dallas.readDevices()) << endl; delay(200); - /* Required to read the temperature once */ float temp[2] = {0, 0}; - float* pFloat = temp; - for(int i=0; i < 10; i++) { - if (dallas.readAllTemperatures(pFloat, 2) > 0) { + float *pFloat = temp; + for (int i = 0; i < 10; i++) + { + if (dallas.readAllTemperatures(pFloat, 2) > 0) + { Serial << "t1: " << String(temp[0]) << endl; Serial << "t2: " << String(temp[1]) << endl; // first read returns crap, ignore result and read again - if (i <= 2) { + if (i <= 2) + { temp1.add(temp[0]); temp2.add(temp[1]); } @@ -352,81 +403,93 @@ void readSensors() { } /* Use the Ultrasonic sensor to measure waterLevel */ - - digitalWrite(SENSOR_SR04_TRIG, LOW); - delayMicroseconds(2); - digitalWrite(SENSOR_SR04_TRIG, HIGH); - delayMicroseconds(10); - digitalWrite(SENSOR_SR04_TRIG, LOW); - float duration = pulseIn(SENSOR_SR04_ECHO, HIGH); - waterRawSensor.add((duration*.343)/2); - Serial << "Distance sensor " << duration << " ms : " << waterRawSensor.getAverage() << " cm" << endl; + for (int i = 0; i < 5; i++) + { + digitalWrite(SENSOR_SR04_TRIG, LOW); + delayMicroseconds(2); + digitalWrite(SENSOR_SR04_TRIG, HIGH); + delayMicroseconds(10); + digitalWrite(SENSOR_SR04_TRIG, LOW); + float duration = pulseIn(SENSOR_SR04_ECHO, HIGH); + waterRawSensor.add((duration * .343) / 2); + Serial << "Distance sensor " << duration << " ms : " << waterRawSensor.getAverage() << " cm" << endl; + delay(20); + } /* deactivate the sensors */ digitalWrite(OUTPUT_SENSOR, LOW); } //Homie.getMqttClient().disconnect(); -void onHomieEvent(const HomieEvent& event) { - switch(event.type) { - case HomieEventType::SENDING_STATISTICS: - Homie.getLogger() << "My statistics" << endl; - break; - case HomieEventType::MQTT_READY: - //wait for rtc sync? - rtcDeepSleepTime = deepSleepTime.get(); - Serial << "MQTT ready " << rtcDeepSleepTime << " ms ds" << endl; - for(int i=0; i < MAX_PLANTS; i++) { - mPlants[i].postMQTTconnection(); - } +void onHomieEvent(const HomieEvent &event) +{ + switch (event.type) + { + case HomieEventType::SENDING_STATISTICS: + Homie.getLogger() << "My statistics" << endl; + break; + case HomieEventType::MQTT_READY: + //wait for rtc sync? + rtcDeepSleepTime = deepSleepTime.get(); + Serial << "MQTT ready " << rtcDeepSleepTime << " ms ds" << endl; + for (int i = 0; i < MAX_PLANTS; i++) + { + mPlants[i].postMQTTconnection(); + } - mode2MQTT(); - break; - case HomieEventType::READY_TO_SLEEP: - Homie.getLogger() << "rtsleep" << endl; - esp_deep_sleep_start(); - break; - case HomieEventType::OTA_STARTED: - digitalWrite(OUTPUT_SENSOR, HIGH); - digitalWrite(OUTPUT_PUMP, LOW); - gpio_hold_dis(GPIO_NUM_13); //pump pwr - gpio_deep_sleep_hold_dis(); - for (int i=0; i < MAX_PLANTS; i++) { - mPlants[i].deactivatePump(); - } - mode3Active=true; - break; - case HomieEventType::OTA_SUCCESSFUL: - digitalWrite(OUTPUT_SENSOR, LOW); - digitalWrite(OUTPUT_PUMP, LOW); - ESP.restart(); - break; - default: - break; + mode2MQTT(); + break; + case HomieEventType::READY_TO_SLEEP: + Homie.getLogger() << "rtsleep" << endl; + esp_deep_sleep_start(); + break; + case HomieEventType::OTA_STARTED: + digitalWrite(OUTPUT_SENSOR, HIGH); + digitalWrite(OUTPUT_PUMP, LOW); + gpio_hold_dis(GPIO_NUM_13); //pump pwr + gpio_deep_sleep_hold_dis(); + for (int i = 0; i < MAX_PLANTS; i++) + { + mPlants[i].deactivatePump(); + } + mode3Active = true; + break; + case HomieEventType::OTA_SUCCESSFUL: + digitalWrite(OUTPUT_SENSOR, LOW); + digitalWrite(OUTPUT_PUMP, LOW); + ESP.restart(); + break; + default: + break; } } -int determineNextPump(){ +int determineNextPump() +{ float solarValue = getSolarVoltage(); - bool isLowLight =(solarValue > SOLAR_CHARGE_MIN_VOLTAGE || solarValue < SOLAR_CHARGE_MAX_VOLTAGE); + bool isLowLight = (solarValue > SOLAR_CHARGE_MIN_VOLTAGE || solarValue < SOLAR_CHARGE_MAX_VOLTAGE); //FIXME instead of for, use sorted by last activation index to ensure equal runtime? - for(int i=0; i < MAX_PLANTS; i++) { + for (int i = 0; i < MAX_PLANTS; i++) + { long lastActivation = getLastActivationForPump(i); - long sinceLastActivation = getCurrentTime()-lastActivation; + long sinceLastActivation = getCurrentTime() - lastActivation; //this pump is in cooldown skip it and disable low power mode trigger for it - if(mPlants[i].isInCooldown(sinceLastActivation) ){ + if (mPlants[i].isInCooldown(sinceLastActivation)) + { Serial.printf("%d Skipping due to cooldown\r\n", i); setMoistureTrigger(i, DEACTIVATED_PLANT); continue; } //skip as it is not low light - if(!isLowLight && mPlants[i].isAllowedOnlyAtLowLight()){ + if (!isLowLight && mPlants[i].isAllowedOnlyAtLowLight()) + { Serial.println("Skipping due to light"); continue; } - if(mPlants->isPumpRequired()){ + if (mPlants->isPumpRequired()) + { Serial.printf("%d Requested pumping\r\n", i); return i; } @@ -443,81 +506,89 @@ int determineNextPump(){ * @return true when the command was parsed and executed succuessfully * @return false on errors when parsing the request */ -bool aliveHandler(const HomieRange& range, const String& value) { - if (range.isRange) return false; // only one controller is present - Serial << value << endl; - if (value.equals("ON") || value.equals("On") || value.equals("1")) { - mode3Active=true; - } else { - mode3Active=false; +bool aliveHandler(const HomieRange &range, const String &value) +{ + if (range.isRange) + return false; // only one controller is present + Serial << value << endl; + if (value.equals("ON") || value.equals("On") || value.equals("1")) + { + mode3Active = true; } - + else + { + mode3Active = false; + } + return true; } -void homieLoop(){ - +void homieLoop() +{ } -void systemInit(){ +void systemInit() +{ WiFi.mode(WIFI_STA); Homie_setFirmware("PlantControl", FIRMWARE_VERSION); // Set default values - + //in seconds deepSleepTime.setDefaultValue(10); deepSleepNightTime.setDefaultValue(30); wateringDeepSleep.setDefaultValue(5); - /* waterLevelMax 1000 */ /* 100cm in mm */ - waterLevelMin.setDefaultValue(50); /* 5cm in mm */ - waterLevelWarn.setDefaultValue(500); /* 50cm in mm */ - waterLevelVol.setDefaultValue(5000); /* 5l in ml */ + /* waterLevelMax 1000 */ /* 100cm in mm */ + waterLevelMin.setDefaultValue(50); /* 5cm in mm */ + waterLevelWarn.setDefaultValue(500); /* 50cm in mm */ + waterLevelVol.setDefaultValue(5000); /* 5l in ml */ Homie.setLoopFunction(homieLoop); Homie.onEvent(onHomieEvent); Homie.setup(); mConfigured = Homie.isConfigured(); - if (mConfigured) { - for(int i=0; i < MAX_PLANTS; i++) { + if (mConfigured) + { + for (int i = 0; i < MAX_PLANTS; i++) + { mPlants[i].advertise(); } sensorTemp.advertise("control") - .setName("Temperature") - .setDatatype("number") - .setUnit("°C"); + .setName("Temperature") + .setDatatype("number") + .setUnit("°C"); sensorTemp.advertise("temp") - .setName("Temperature") - .setDatatype("number") - .setUnit("°C"); + .setName("Temperature") + .setDatatype("number") + .setUnit("°C"); sensorLipo.advertise("percent") - .setName("Percent") - .setDatatype("number") - .setUnit("%"); + .setName("Percent") + .setDatatype("number") + .setUnit("%"); sensorLipo.advertise("volt") - .setName("Volt") - .setDatatype("number") - .setUnit("V"); + .setName("Volt") + .setDatatype("number") + .setUnit("V"); sensorSolar.advertise("percent") - .setName("Percent") - .setDatatype("number") - .setUnit("%"); + .setName("Percent") + .setDatatype("number") + .setUnit("%"); sensorSolar.advertise("volt") - .setName("Volt") - .setDatatype("number") - .setUnit("V"); + .setName("Volt") + .setDatatype("number") + .setUnit("V"); sensorWater.advertise("remaining").setDatatype("number").setUnit("%"); } stayAlive.advertise("alive").setName("Alive").setDatatype("number").settable(aliveHandler); } - -bool mode1(){ +bool mode1() +{ Serial.println("m1"); Serial << getCurrentTime() << " curtime" << endl; @@ -525,7 +596,7 @@ bool mode1(){ gpio_deep_sleep_hold_dis(); readSensors(); - //queue sensor values for + //queue sensor values for if ((rtcDeepSleepTime == 0) || (rtcMoistureTrigger0 == 0) || @@ -534,62 +605,72 @@ bool mode1(){ (rtcMoistureTrigger3 == 0) || (rtcMoistureTrigger4 == 0) || (rtcMoistureTrigger5 == 0) || - (rtcMoistureTrigger6 == 0) - ) + (rtcMoistureTrigger6 == 0)) { - Serial.println("RTCm2"); - return true; + Serial.println("RTCm2"); + return true; } - - if ((rtcMoistureTrigger0 != DEACTIVATED_PLANT) && (mPlants[0].getSensorValue() < rtcMoistureTrigger0) ) { + + if ((rtcMoistureTrigger0 != DEACTIVATED_PLANT) && (mPlants[0].getSensorValue() < rtcMoistureTrigger0)) + { Serial.println("mt0"); return true; } - if ((rtcMoistureTrigger1 != DEACTIVATED_PLANT) && (mPlants[1].getSensorValue() < rtcMoistureTrigger1) ) { + if ((rtcMoistureTrigger1 != DEACTIVATED_PLANT) && (mPlants[1].getSensorValue() < rtcMoistureTrigger1)) + { Serial.println("mt1"); return true; } - if ((rtcMoistureTrigger2 != DEACTIVATED_PLANT) && (mPlants[2].getSensorValue() < rtcMoistureTrigger2) ) { + if ((rtcMoistureTrigger2 != DEACTIVATED_PLANT) && (mPlants[2].getSensorValue() < rtcMoistureTrigger2)) + { Serial.println("mt2"); return true; } - if ((rtcMoistureTrigger3 != DEACTIVATED_PLANT) && (mPlants[3].getSensorValue() < rtcMoistureTrigger3) ) { + if ((rtcMoistureTrigger3 != DEACTIVATED_PLANT) && (mPlants[3].getSensorValue() < rtcMoistureTrigger3)) + { Serial.println("mt3"); return true; } - if ((rtcMoistureTrigger4 != DEACTIVATED_PLANT) && (mPlants[4].getSensorValue() < rtcMoistureTrigger4) ) { + if ((rtcMoistureTrigger4 != DEACTIVATED_PLANT) && (mPlants[4].getSensorValue() < rtcMoistureTrigger4)) + { Serial.println("mt4"); return true; } - if ((rtcMoistureTrigger5 != DEACTIVATED_PLANT) && (mPlants[5].getSensorValue() < rtcMoistureTrigger5) ) { + if ((rtcMoistureTrigger5 != DEACTIVATED_PLANT) && (mPlants[5].getSensorValue() < rtcMoistureTrigger5)) + { Serial.println("mt5"); return true; } - if ((rtcMoistureTrigger6 != DEACTIVATED_PLANT) && (mPlants[6].getSensorValue() < rtcMoistureTrigger6) ) { + if ((rtcMoistureTrigger6 != DEACTIVATED_PLANT) && (mPlants[6].getSensorValue() < rtcMoistureTrigger6)) + { Serial.println("mt6"); return true; } //check how long it was already in mode1 if to long goto mode2 long cTime = getCurrentTime(); - if(cTime < 100000){ + if (cTime < 100000) + { Serial.println("Starting mode 2 due to missing ntp"); //missing ntp time boot to mode3 return true; } - if(gotoMode2AfterThisTimestamp < cTime){ + if (gotoMode2AfterThisTimestamp < cTime) + { Serial.println("Starting mode 2 after specified mode1 time"); return true; } return false; } -void mode2(){ +void mode2() +{ Serial.println("m2"); systemInit(); /* Jump into Mode 3, if not configured */ - if (!mConfigured) { + if (!mConfigured) + { Serial.println("m3"); mode3Active = true; } @@ -599,12 +680,15 @@ void mode2(){ * @brief Startup function * Is called once, the controller is started */ -void setup() { +void setup() +{ Serial.begin(115200); Serial.setTimeout(1000); // Set timeout of 1 second - Serial << endl << endl; + Serial << endl + << endl; /* Intialize Plant */ - for(int i=0; i < MAX_PLANTS; i++) { + for (int i = 0; i < MAX_PLANTS; i++) + { mPlants[i].init(); } @@ -616,11 +700,12 @@ void setup() { /* Power pins */ pinMode(OUTPUT_PUMP, OUTPUT); - + /* Disable Wifi and bluetooth */ WiFi.mode(WIFI_OFF); - if (HomieInternals::MAX_CONFIG_SETTING_SIZE < MAX_CONFIG_SETTING_ITEMS) { + if (HomieInternals::MAX_CONFIG_SETTING_SIZE < MAX_CONFIG_SETTING_ITEMS) + { //increase the config settings to 50 and the json to 3000 Serial << "Limits.hpp" << endl; } @@ -628,20 +713,24 @@ void setup() { // Big TODO use here the settings in RTC_Memory //Panik mode, the Lipo is empty, sleep a long long time: - if ((getBatteryVoltage() < MINIMUM_LIPO_VOLT) && - (getBatteryVoltage() > NO_LIPO_VOLT)) { + if ((getBatteryVoltage() < MINIMUM_LIPO_VOLT) && + (getBatteryVoltage() > NO_LIPO_VOLT)) + { Serial << PANIK_MODE_DEEPSLEEP << " s lipo " << getBatteryVoltage() << "V" << endl; esp_sleep_enable_timer_wakeup(PANIK_MODE_DEEPSLEEP_US); esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF); esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_FAST_MEM, ESP_PD_OPTION_OFF); - esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL,ESP_PD_OPTION_ON); + esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_ON); esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_OFF); esp_deep_sleep_start(); } - if(mode1()){ + if (mode1()) + { mode2(); - } else { + } + else + { Serial.println("nop"); Serial.flush(); esp_deep_sleep_start(); @@ -653,15 +742,20 @@ void setup() { * Executs the Homie base functionallity or triggers sleeping, if requested. */ -void loop() { - if (!mDeepsleep) { +void loop() +{ + if (!mDeepsleep) + { Homie.loop(); - } else { + } + else + { esp_deep_sleep_start(); } - if(millis() > 30000 && !mode3Active){ - Serial << (millis()/ 1000) << "s alive" << endl; + if (millis() > 30000 && !mode3Active) + { + Serial << (millis() / 1000) << "s alive" << endl; Serial.flush(); esp_deep_sleep_start(); }