Merge branch 'hydro'
# Conflicts: # esp32/PlantControl.code-workspace # esp32/include/ControllerConfiguration.h # esp32/platformio.ini # esp32/src/main.cpp
This commit is contained in:
@@ -47,7 +47,7 @@ void Plant::init(void)
|
||||
this->mSetting->pPumpDuration->setDefaultValue(30);
|
||||
this->mSetting->pPumpDuration->setValidator([](long candidate)
|
||||
{ return ((candidate >= 0) && (candidate <= 1000)); });
|
||||
this->mSetting->pPumpMl->setDefaultValue(0);
|
||||
this->mSetting->pPumpMl->setDefaultValue(1000);
|
||||
this->mSetting->pPumpMl->setValidator([](long candidate)
|
||||
{ return ((candidate >= 0) && (candidate <= 5000)); });
|
||||
this->mSetting->pPumpPowerLevel->setDefaultValue(100);
|
||||
@@ -91,7 +91,6 @@ void Plant::initSensors(void)
|
||||
adcAttachPin(this->mPinSensor);
|
||||
break;
|
||||
}
|
||||
case SHT20:
|
||||
case NONE:
|
||||
{
|
||||
// do nothing
|
||||
@@ -113,34 +112,6 @@ void Plant::blockingMoistureMeasurement(void)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SHT20:
|
||||
{
|
||||
|
||||
//do not assume valid i2c state, reinit
|
||||
TwoWire sensorWire = TwoWire(0);
|
||||
sensorWire.setPins(SENSOR_TANK_SDA, SHARED_SCL);
|
||||
sht20.begin(&sensorWire);
|
||||
sht20.reset();
|
||||
delay(100);
|
||||
if(!sht20.isConnected()){
|
||||
Serial.println("SHT20 connection error");
|
||||
}
|
||||
bool success = sht20.read();
|
||||
int error = sht20.getError();
|
||||
if (error)
|
||||
{
|
||||
log(LOG_LEVEL_ERROR, "Failure reading SHT20 " + String(error), LOG_SENSOR_MISSING);
|
||||
}
|
||||
if (!success || error)
|
||||
{
|
||||
this->mMoisture_raw.clear();
|
||||
this->mMoisture_raw.add(MISSING_SENSOR);
|
||||
return;
|
||||
}
|
||||
mMoisture_raw.add(sht20.getHumidity());
|
||||
mTemperature_degree.add(sht20.getTemperature());
|
||||
break;
|
||||
}
|
||||
case CAPACITIVE_FREQUENCY:
|
||||
case NONE:
|
||||
{
|
||||
@@ -160,7 +131,6 @@ void Plant::startMoistureMeasurement(void)
|
||||
pcnt_counter_resume(unit);
|
||||
break;
|
||||
}
|
||||
case SHT20:
|
||||
case ANALOG_RESISTANCE_PROBE:
|
||||
case NONE:
|
||||
{
|
||||
@@ -192,7 +162,6 @@ void Plant::stopMoistureMeasurement(void)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SHT20:
|
||||
case ANALOG_RESISTANCE_PROBE:
|
||||
case NONE:
|
||||
{
|
||||
|
@@ -35,12 +35,18 @@
|
||||
#include <VL53L0X.h>
|
||||
#include "driver/pcnt.h"
|
||||
#include "MQTTUtils.h"
|
||||
#include "esp_ota_ops.h"
|
||||
#if defined(TIMED_LIGHT_PIN)
|
||||
#include "ulp-pwm.h"
|
||||
#endif
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* DEFINES
|
||||
******************************************************************************/
|
||||
#define AMOUNT_SENOR_QUERYS 8
|
||||
#define MAX_TANK_DEPTH 2000
|
||||
#define REBOOT_LOOP_DETECTION_ERROR 5
|
||||
|
||||
/******************************************************************************
|
||||
* FUNCTION PROTOTYPES
|
||||
@@ -54,9 +60,7 @@ bool determineTimedLightState(bool lowLight);
|
||||
/******************************************************************************
|
||||
* NON VOLATILE VARIABLES in DEEP SLEEP
|
||||
******************************************************************************/
|
||||
|
||||
#if defined(TIMED_LIGHT_PIN)
|
||||
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 */
|
||||
#endif // TIMED_LIGHT_PIN
|
||||
|
||||
@@ -80,6 +84,7 @@ unsigned long setupFinishedTimestamp;
|
||||
|
||||
bool pumpStarted = false;
|
||||
long pumpTarget = -1;
|
||||
long pumpStartTime = 0;
|
||||
long lastSendPumpUpdate = 0;
|
||||
#ifdef FLOWMETER_PIN
|
||||
long pumpTargetMl = -1;
|
||||
@@ -127,11 +132,28 @@ Plant mPlants[MAX_PLANTS] = {
|
||||
* LOCAL FUNCTIONS
|
||||
******************************************************************************/
|
||||
|
||||
void finsihedCycleSucessfully()
|
||||
{
|
||||
const esp_partition_t *running = esp_ota_get_running_partition();
|
||||
esp_ota_img_states_t ota_state;
|
||||
if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK)
|
||||
{
|
||||
log(LOG_LEVEL_INFO, "Get State Partition was Successfull", LOG_BOOT_ERROR_DETECTION);
|
||||
if (ota_state == ESP_OTA_IMG_PENDING_VERIFY)
|
||||
{
|
||||
log(LOG_LEVEL_INFO, "Diagnostics completed successfully! Marking as valid", LOG_BOOT_ERROR_DETECTION);
|
||||
esp_ota_mark_app_valid_cancel_rollback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void espDeepSleep(bool afterPump = false)
|
||||
{
|
||||
if (mDownloadMode)
|
||||
{
|
||||
log(LOG_LEVEL_DEBUG, "abort deepsleep, DownloadMode active", LOG_DEBUG_CODE);
|
||||
//if we manage to get to the download mode, the device can be restored
|
||||
finsihedCycleSucessfully();
|
||||
return;
|
||||
}
|
||||
if (aliveWasRead())
|
||||
@@ -154,17 +176,7 @@ void espDeepSleep(bool afterPump = false)
|
||||
}
|
||||
}
|
||||
|
||||
//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);
|
||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_FAST_MEM, ESP_PD_OPTION_ON);
|
||||
esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_ON);
|
||||
|
||||
#if defined(TIMED_LIGHT_PIN)
|
||||
gpio_hold_en(TIMED_LIGHT_PIN);
|
||||
#endif // TIMED_LIGHT_PIN
|
||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||
|
||||
long secondsToSleep = -1;
|
||||
|
||||
@@ -187,6 +199,7 @@ void espDeepSleep(bool afterPump = false)
|
||||
}
|
||||
}
|
||||
|
||||
finsihedCycleSucessfully();
|
||||
esp_sleep_enable_timer_wakeup((secondsToSleep * 1000U * 1000U));
|
||||
if (aliveWasRead())
|
||||
{
|
||||
@@ -310,22 +323,12 @@ void readPowerSwitchedSensors()
|
||||
Serial << "Plant " << i << " measurement: " << mPlants[i].getCurrentMoistureRaw() << " mV " << mPlants[i].getCurrentMoisturePCT() << "%" << endl;
|
||||
break;
|
||||
}
|
||||
case SHT20:{
|
||||
Serial << "Plant " << i << " measurement: " << mPlants[i].getCurrentTemperature() << "°C " << mPlants[i].getCurrentMoisturePCT() << "rH%" << endl;
|
||||
break;
|
||||
}
|
||||
|
||||
case NONE : {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//do not assume valid i2c state, force release of hardware
|
||||
Wire = TwoWire(0);
|
||||
Wire.setPins(SENSOR_TANK_SDA, SHARED_SCL);
|
||||
Wire.begin();
|
||||
|
||||
waterRawSensor.clear();
|
||||
tankSensor.setTimeout(500);
|
||||
long start = millis();
|
||||
@@ -485,7 +488,12 @@ int determineNextPump(bool isLowLight)
|
||||
}
|
||||
else
|
||||
{
|
||||
plant.publishState("active");
|
||||
if(mDownloadMode){
|
||||
plant.publishState("active+supressed");
|
||||
}else {
|
||||
plant.publishState("active");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!plant.isHydroponic())
|
||||
@@ -603,7 +611,7 @@ void initPumpLogic()
|
||||
//set targets
|
||||
|
||||
#ifdef FLOWMETER_PIN
|
||||
pumpTargetMl = mPlants[pumpToRun].getPumpDuration();
|
||||
pumpTargetMl = mPlants[pumpToRun].getPumpMl();
|
||||
|
||||
//0-6 are used for moisture measurment
|
||||
pcnt_unit_t unit = (pcnt_unit_t)(PCNT_UNIT_7);
|
||||
@@ -613,8 +621,8 @@ void initPumpLogic()
|
||||
pcnt_config.unit = unit; // Unidade de contagem PCNT - 0
|
||||
pcnt_config.channel = PCNT_CHANNEL_0; // Canal de contagem PCNT - 0
|
||||
pcnt_config.counter_h_lim = INT16_MAX; // Limite maximo de contagem - 20000
|
||||
pcnt_config.pos_mode = PCNT_COUNT_DIS; // Incrementa contagem na subida do pulso
|
||||
pcnt_config.neg_mode = PCNT_COUNT_INC; // Incrementa contagem na descida do pulso
|
||||
pcnt_config.pos_mode = PCNT_COUNT_INC; // Incrementa contagem na subida do pulso
|
||||
pcnt_config.neg_mode = PCNT_COUNT_DIS; // Incrementa contagem na descida do pulso
|
||||
pcnt_config.lctrl_mode = PCNT_MODE_KEEP; // PCNT - modo lctrl desabilitado
|
||||
pcnt_config.hctrl_mode = PCNT_MODE_KEEP; // PCNT - modo hctrl - se HIGH conta incrementando
|
||||
pcnt_unit_config(&pcnt_config); // Configura o contador PCNT
|
||||
@@ -622,8 +630,14 @@ void initPumpLogic()
|
||||
pcnt_counter_clear(unit); // Zera o contador PCNT
|
||||
pcnt_counter_resume(unit);
|
||||
#endif
|
||||
pumpStartTime = millis();
|
||||
pumpTarget = millis() + (mPlants[pumpToRun].getPumpDuration() * 1000);
|
||||
log(LOG_LEVEL_INFO, "Starting pump " + String(pumpToRun) + " for " + String(mPlants[pumpToRun].getPumpDuration()) + "s", LOG_PUMP_STARTED_CODE);
|
||||
#ifdef FLOWMETER_PIN
|
||||
log(LOG_LEVEL_INFO, "Starting pump " + String(pumpToRun) + " for " + String(mPlants[pumpToRun].getPumpDuration()) + "s or " + String(pumpTargetMl) + "ml", LOG_PUMP_STARTED_CODE);
|
||||
#else
|
||||
log(LOG_LEVEL_INFO, "Starting pump " + String(pumpToRun) + " for " + String(mPlants[pumpToRun].getPumpDuration()) + "s", LOG_PUMP_STARTED_CODE);
|
||||
#endif
|
||||
|
||||
|
||||
//enable power
|
||||
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
|
||||
@@ -652,8 +666,8 @@ void pumpActiveLoop()
|
||||
mqttUpdateTick = true;
|
||||
}
|
||||
|
||||
long duration = millis() - pumpStartTime;
|
||||
#ifdef FLOWMETER_PIN
|
||||
|
||||
int16_t pulses;
|
||||
pcnt_unit_t unit = (pcnt_unit_t)(PCNT_UNIT_7);
|
||||
esp_err_t result = pcnt_get_counter_value(unit, &pulses);
|
||||
@@ -661,29 +675,29 @@ void pumpActiveLoop()
|
||||
{
|
||||
log(LOG_LEVEL_ERROR, LOG_HARDWARECOUNTER_ERROR_MESSAGE, LOG_HARDWARECOUNTER_ERROR_CODE);
|
||||
targetReached = true;
|
||||
log(LOG_LEVEL_INFO, "Reached pump target ml " + String(pumpToRun), LOG_PUMP_STARTED_CODE);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/**FLOWMETER_FLOWFACTOR * (L/Min) = F;
|
||||
given 1L/min -> FLOWMETER_FLOWFACTOR*60 pulses per liter
|
||||
-> 1000/result -> ml pro pulse;
|
||||
-> result * pulses ->*/
|
||||
long pumped = (FLOWMETER_FLOWFACTOR * 60) * pulses / 1000;
|
||||
if (pumped >= pumpTargetMl)
|
||||
float mLPumped = pulses/FLOWMETER_PULSES_PER_ML; //mLperMs*duration;
|
||||
if (mLPumped >= pumpTargetMl)
|
||||
{
|
||||
targetReached = true;
|
||||
pcnt_counter_pause(unit);
|
||||
mPlants[pumpToRun].setProperty("waterusage").send(String(pumped));
|
||||
mPlants[pumpToRun].setProperty("pulses").send(String(pulses));
|
||||
mPlants[pumpToRun].setProperty("waterusage").send(String(mLPumped));
|
||||
}
|
||||
|
||||
else if (mqttUpdateTick)
|
||||
{
|
||||
mPlants[pumpToRun].setProperty("waterusage").send(String(pumped));
|
||||
mPlants[pumpToRun].setProperty("pulses").send(String(pulses));
|
||||
mPlants[pumpToRun].setProperty("waterusage").send(String(mLPumped));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
long pumpStarted = pumpTarget - (mPlants[pumpToRun].getPumpDuration() * 1000);
|
||||
long duration = millis() - pumpStarted;
|
||||
|
||||
if (millis() > pumpTarget)
|
||||
{
|
||||
mPlants[pumpToRun].setProperty("watertime").send(String(duration));
|
||||
@@ -696,12 +710,10 @@ void pumpActiveLoop()
|
||||
|
||||
if (targetReached)
|
||||
{
|
||||
|
||||
//disable all
|
||||
digitalWrite(OUTPUT_ENABLE_PUMP, LOW);
|
||||
for (int i = 0; i < MAX_PLANTS; i++)
|
||||
{
|
||||
mPlants[i].deactivatePump();
|
||||
}
|
||||
mPlants[pumpToRun].deactivatePump();
|
||||
//disable loop, to prevent multi processing
|
||||
pumpStarted = false;
|
||||
//if runtime is larger than cooldown, else it would run continously
|
||||
@@ -723,9 +735,7 @@ void safeSetup()
|
||||
|
||||
//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);
|
||||
ulp_pwm_init();
|
||||
#endif // TIMED_LIGHT_PIN
|
||||
|
||||
/* Intialize Plant */
|
||||
@@ -778,13 +788,15 @@ void safeSetup()
|
||||
{ return (candidate > 0) && (candidate < (20)); });
|
||||
|
||||
#if defined(TIMED_LIGHT_PIN)
|
||||
timedLightPowerLevel.setDefaultValue(25).setValidator([](long candidate)
|
||||
{ return (candidate > 0) && (candidate <= (255)); });
|
||||
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)); });
|
||||
{ return ((candidate > 3.3 || candidate == -1) && (candidate < (50))); });
|
||||
#endif // TIMED_LIGHT_PIN
|
||||
|
||||
Homie.setLoopFunction(homieLoop);
|
||||
@@ -800,6 +812,9 @@ void safeSetup()
|
||||
|
||||
Homie.setup();
|
||||
|
||||
Wire = TwoWire(0);
|
||||
Wire.setPins(SENSOR_TANK_SDA, SENSOR_TANK_SCL);
|
||||
Wire.begin();
|
||||
|
||||
|
||||
/************************* Start One-Wire bus ***************/
|
||||
@@ -830,10 +845,6 @@ void safeSetup()
|
||||
for (int i = 0; i < MAX_PLANTS; i++)
|
||||
{
|
||||
mPlants[i].advertise();
|
||||
//write to temperature node instead
|
||||
if(!equalish(mPlants[i].getCurrentTemperature(),PLANT_WITHOUT_TEMPSENSOR)){
|
||||
mqttWrite(&sensorTemp, "Plant" + String(i), String(mPlants[i].getCurrentTemperature()));
|
||||
}
|
||||
}
|
||||
mPlants[0].setSwitchHandler(switch1);
|
||||
mPlants[1].setSwitchHandler(switch2);
|
||||
@@ -1056,7 +1067,17 @@ void plantcontrol()
|
||||
Serial.flush();
|
||||
}
|
||||
|
||||
bool isLowLight = (mSolarVoltage < SOLAR_CHARGE_MIN_VOLTAGE);
|
||||
#if defined(TIMED_LIGHT_PIN)
|
||||
bool isLowLight = mSolarVoltage <= 9;
|
||||
bool shouldLight = determineTimedLightState(isLowLight);
|
||||
if(shouldLight){
|
||||
ulp_pwm_set_level(timedLightPowerLevel.get());
|
||||
}else {
|
||||
ulp_pwm_set_level(0);
|
||||
}
|
||||
|
||||
#endif // TIMED_LIGHT_PIN
|
||||
|
||||
bool hasWater = true; //FIXME remaining > waterLevelMin.get();
|
||||
//FIXME no water warning message
|
||||
pumpToRun = determineNextPump(isLowLight);
|
||||
@@ -1083,12 +1104,6 @@ void plantcontrol()
|
||||
{
|
||||
espDeepSleep();
|
||||
}
|
||||
|
||||
#if defined(TIMED_LIGHT_PIN)
|
||||
bool shouldLight = determineTimedLightState(isLowLight);
|
||||
timedLightOn = shouldLight;
|
||||
digitalWrite(TIMED_LIGHT_PIN, shouldLight);
|
||||
#endif // TIMED_LIGHT_PIN
|
||||
}
|
||||
|
||||
/** @}*/
|
||||
@@ -1113,13 +1128,17 @@ bool determineTimedLightState(bool lowLight)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (((hoursStart > hoursEnd) &&
|
||||
(getCurrentHour() >= hoursStart || getCurrentHour() <= hoursEnd)) ||
|
||||
/* Handle e.g. start = 8, end = 21 */
|
||||
int curHour = getCurrentHour();
|
||||
bool condition1 = ((hoursStart > hoursEnd) &&
|
||||
(curHour >= hoursStart || curHour <= hoursEnd));
|
||||
bool condition2 = /* Handle e.g. start = 8, end = 21 */
|
||||
((hoursStart < hoursEnd) &&
|
||||
(getCurrentHour() >= hoursStart && getCurrentHour() <= hoursEnd)))
|
||||
(curHour >= hoursStart && curHour <= hoursEnd));
|
||||
timedLightNode.setProperty("debug").send(String(curHour) + " " + String(hoursStart) + " " + String(hoursEnd) + " " + String(condition1) + " " + String(condition2));
|
||||
if (condition1 || condition2)
|
||||
{
|
||||
if (!timedLightLowVoltageTriggered && battery.getVoltage(BATTSENSOR_INDEX_BATTERY) >= timedLightVoltageCutoff.get())
|
||||
bool voltageOk = !timedLightLowVoltageTriggered && battery.getVoltage(BATTSENSOR_INDEX_BATTERY) >= timedLightVoltageCutoff.get();
|
||||
if (voltageOk || equalish(timedLightVoltageCutoff.get(), -1))
|
||||
{
|
||||
timedLightNode.setProperty("state").send(String("On"));
|
||||
return true;
|
||||
|
Reference in New Issue
Block a user