diff --git a/esp32/include/ControllerConfiguration.h b/esp32/include/ControllerConfiguration.h index e3d7479..f3b4020 100644 --- a/esp32/include/ControllerConfiguration.h +++ b/esp32/include/ControllerConfiguration.h @@ -21,8 +21,8 @@ #define OUTPUT_ENABLE_PUMP GPIO_NUM_13 /**< GPIO 13 - Enable Pumps */ #define SENSOR_ONEWIRE GPIO_NUM_4 /**< GPIO 12 - Temperatur sensor, Battery and other cool onewire stuff */ -#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 SHARED_SCL GPIO_NUM_16 /**< GPIO 16 - echo feedback of water sensor */ +#define SENSOR_TANK_SDA GPIO_NUM_17 /**< GPIO 17 - trigger for water sensor */ #define BUTTON GPIO_NUM_0 /**< GPIO 0 - Fix button of NodeMCU */ #define CUSTOM1_PIN1 GPIO_NUM_34 /** direct gpio */ @@ -65,6 +65,8 @@ #define TEMPERATUR_TIMEOUT 3000 /**< 3 Seconds timeout for the temperatur sensors */ #define DS18B20_RESOLUTION 9 /**< 9bit temperature resolution -> 0.5°C steps */ +#define PLANT_WITHOUT_TEMPSENSOR 100 + #define UTC_OFFSET_DE 3600 /* UTC offset in seconds for Germany */ #define UTF_OFFSET_DE_DST 3600 /* offset in seconds if daylight saving time is active */ diff --git a/esp32/include/HomieConfiguration.h b/esp32/include/HomieConfiguration.h index 14028b5..124d166 100644 --- a/esp32/include/HomieConfiguration.h +++ b/esp32/include/HomieConfiguration.h @@ -101,7 +101,6 @@ HomieSetting ntpServer("ntpServer", "NTP server (pool.ntp.org as d #define GENERATE_PLANT(plant, strplant) \ HomieSetting mSensorDry##plant = HomieSetting("dry" strplant, "Plant " strplant "- Moist sensor dry %"); \ - HomieSetting pSensorType##plant = HomieSetting("sensoryType" strplant, "sensor" strplant " - sensortype"); \ HomieSetting mPumpAllowedHourRangeStart##plant = HomieSetting("hourstart" strplant, "Plant" strplant " - Range pump allowed hour start (0-23)"); \ HomieSetting mPumpAllowedHourRangeEnd##plant = HomieSetting("hourend" strplant, "Plant" strplant " - Range pump allowed hour end (0-23)"); \ HomieSetting mPumpOnlyWhenLowLight##plant = HomieSetting("lowLight" strplant, "Plant" strplant " - Enable the Pump only, when there is no sunlight"); \ @@ -109,7 +108,7 @@ HomieSetting ntpServer("ntpServer", "NTP server (pool.ntp.org as d HomieSetting pPumpDuration##plant = HomieSetting("pumpDuration" strplant, "Plant" strplant " - time seconds to water when pump is active"); \ HomieSetting pPumpMl##plant = HomieSetting("pumpAmount" strplant, "Plant" strplant " - ml (if using flowmeter) to water when pump is active"); \ HomieSetting pPowerLevel##plant = HomieSetting("powerLevel" strplant, "Plant" strplant " - pwm duty cycle in percent"); \ - PlantSettings_t mSetting##plant = {&mSensorDry##plant, &pSensorType##plant, &mPumpAllowedHourRangeStart##plant, &mPumpAllowedHourRangeEnd##plant, &mPumpOnlyWhenLowLight##plant, &mPumpCooldownInMinutes##plant, &pPumpDuration##plant, &pPowerLevel##plant, &pPumpMl##plant}; \ + PlantSettings_t mSetting##plant = {&mSensorDry##plant, &mPumpAllowedHourRangeStart##plant, &mPumpAllowedHourRangeEnd##plant, &mPumpOnlyWhenLowLight##plant, &mPumpCooldownInMinutes##plant, &pPumpDuration##plant, &pPowerLevel##plant, &pPumpMl##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} \ diff --git a/esp32/include/HomieTypes.h b/esp32/include/HomieTypes.h index 2e67460..4fae0cc 100644 --- a/esp32/include/HomieTypes.h +++ b/esp32/include/HomieTypes.h @@ -17,6 +17,7 @@ SENSOR(NONE) \ SENSOR(CAPACITIVE_FREQUENCY) \ SENSOR(ANALOG_RESISTANCE_PROBE) \ + SENSOR(SHT20) #define GENERATE_ENUM(ENUM) ENUM, #define GENERATE_STRING(STRING) #STRING, @@ -39,7 +40,6 @@ static const char *SENSOR_STRING[] = { typedef struct PlantSettings_t { HomieSetting *pSensorDry; - HomieSetting *pSensorMode; HomieSetting *pPumpAllowedHourRangeStart; HomieSetting *pPumpAllowedHourRangeEnd; HomieSetting *pPumpOnlyWhenLowLight; diff --git a/esp32/include/LogDefines.h b/esp32/include/LogDefines.h index c5db217..4e6a9ba 100644 --- a/esp32/include/LogDefines.h +++ b/esp32/include/LogDefines.h @@ -24,6 +24,8 @@ #define LOG_SENSORMODE_UNKNOWN "Unknown sensor mode requested" #define LOG_SENSORMODE_UNKNOWN_CODE -5 +#define LOG_SENSOR_MISSING -6 + #define LOG_PUMP_AND_DOWNLOADMODE "Download mode, ignoring pump request" #define LOG_PUMP_AND_DOWNLOADMODE_CODE 2 diff --git a/esp32/include/PlantCtrl.h b/esp32/include/PlantCtrl.h index f90f5fb..ad928f7 100644 --- a/esp32/include/PlantCtrl.h +++ b/esp32/include/PlantCtrl.h @@ -4,9 +4,9 @@ * @brief Abstraction to handle the Sensors * @version 0.1 * @date 2020-05-27 - * + * * @copyright Copyright (c) 2020 - * + * */ #ifndef PLANT_CTRL_H @@ -19,6 +19,7 @@ #include "MathUtils.h" #include "MQTTUtils.h" #include "LogDefines.h" +#include "SHT2x.h" #define ANALOG_REREADS 5 #define MOISTURE_MEASUREMENT_DURATION 400 /** ms */ @@ -32,31 +33,35 @@ private: HomieNode *mPlant = NULL; HomieInternals::PropertyInterface mPump; RunningMedian mMoisture_raw = RunningMedian(ANALOG_REREADS); + RunningMedian mTemperature_degree = RunningMedian(ANALOG_REREADS); int mPinSensor = 0; /**< Pin of the moist sensor */ int mPinPump = 0; /**< Pin of the pump */ bool mConnected = false; int mPlantId = -1; + SENSOR_MODE mSensorMode; + SHT2x sht20; + public: PlantSettings_t *mSetting; /** * @brief Construct a new Plant object - * + * * @param pinSensor Pin of the Sensor to use to measure moist * @param pinPump Pin of the Pump to use */ Plant(int pinSensor, int pinPump, int plantId, HomieNode *plant, - PlantSettings_t *setting); + PlantSettings_t *setting, SENSOR_MODE mode); void postMQTTconnection(void); void advertise(void); - //for sensor that might take any time + // for sensor that might take any time void blockingMoistureMeasurement(void); - //for sensor that need a start and a end in defined timing + // for sensor that need a start and a end in defined timing void startMoistureMeasurement(void); void stopMoistureMeasurement(void); @@ -64,7 +69,8 @@ public: void activatePump(void); - String getSensorModeString(){ + String getSensorModeString() + { SENSOR_MODE mode = getSensorMode(); return SENSOR_STRING[mode]; } @@ -77,22 +83,20 @@ public: SENSOR_MODE getSensorMode() { - int raw_mode = this->mSetting->pSensorMode->get(); - SENSOR_MODE sensorType = static_cast(raw_mode); - return sensorType; + return mSensorMode; } /** * @brief Check if a plant is too dry and needs some water. - * - * @return true - * @return false + * + * @return true + * @return false */ bool isPumpRequired() { if (isHydroponic()) { - //hydroponic only uses timer based controll + // hydroponic only uses timer based controll return true; } bool isDry = getCurrentMoisturePCT() < getTargetMoisturePCT(); @@ -118,30 +122,39 @@ public: } } + float getCurrentTemperature(){ + if(mTemperature_degree.getCount() == 0){ + return PLANT_WITHOUT_TEMPSENSOR; + } + return mTemperature_degree.getMedian(); + } + float getCurrentMoisturePCT() { - switch (getSensorMode()){ + switch (getSensorMode()) + { case NONE: return DEACTIVATED_PLANT; case CAPACITIVE_FREQUENCY: return mapf(mMoisture_raw.getMedian(), MOIST_SENSOR_MAX_FRQ, MOIST_SENSOR_MIN_FRQ, 0, 100); case ANALOG_RESISTANCE_PROBE: return mapf(mMoisture_raw.getMedian(), ANALOG_SENSOR_MAX_MV, ANALOG_SENSOR_MIN_MV, 0, 100); - default: - log(LOG_LEVEL_ERROR, LOG_SENSORMODE_UNKNOWN, LOG_SENSORMODE_UNKNOWN_CODE); - return DEACTIVATED_PLANT; + case SHT20: + return mMoisture_raw.getMedian(); } + return MISSING_SENSOR; } float getCurrentMoistureRaw() { - if(getSensorMode() == CAPACITIVE_FREQUENCY){ -if (mMoisture_raw.getMedian() < MOIST_SENSOR_MIN_FRQ) + if (getSensorMode() == CAPACITIVE_FREQUENCY) + { + if (mMoisture_raw.getMedian() < MOIST_SENSOR_MIN_FRQ) { return MISSING_SENSOR; } } - + return mMoisture_raw.getMedian(); } @@ -160,8 +173,8 @@ if (mMoisture_raw.getMedian() < MOIST_SENSOR_MIN_FRQ) /** * @brief Get the Hours when pumping should start - * - * @return hour + * + * @return hour */ int getHoursStart() { @@ -170,8 +183,8 @@ if (mMoisture_raw.getMedian() < MOIST_SENSOR_MIN_FRQ) /** * @brief Get the Hours when pumping should end - * - * @return hour + * + * @return hour */ int getHoursEnd() { diff --git a/esp32/platformio.ini b/esp32/platformio.ini index c6aac22..28cdfff 100644 --- a/esp32/platformio.ini +++ b/esp32/platformio.ini @@ -22,6 +22,7 @@ lib_deps = ArduinoJson@6.16.1 DallasTemperature pololu/VL53L0X https://github.com/homieiot/homie-esp8266.git#develop + robtillaart/SHT2x@^0.1.3 [platformio] diff --git a/esp32/src/PlantCtrl.cpp b/esp32/src/PlantCtrl.cpp index 4e50775..a7d0e93 100644 --- a/esp32/src/PlantCtrl.cpp +++ b/esp32/src/PlantCtrl.cpp @@ -1,26 +1,29 @@ /** * @file PlantCtrl.cpp * @author your name (you@domain.com) - * @brief + * @brief * @version 0.1 * @date 2020-05-27 - * + * * @copyright Copyright (c) 2020 - * + * */ #include "PlantCtrl.h" #include "ControllerConfiguration.h" #include "TimeUtils.h" #include "driver/pcnt.h" +#include "MQTTUtils.h" -Plant::Plant(int pinSensor, int pinPump, int plantId, HomieNode *plant, PlantSettings_t *setting) +Plant::Plant(int pinSensor, int pinPump, int plantId, HomieNode *plant, PlantSettings_t *setting, SENSOR_MODE mode) { this->mPinSensor = pinSensor; this->mPinPump = pinPump; this->mPlant = plant; this->mSetting = setting; this->mPlantId = plantId; + this->mSensorMode = mode; + this->sht20 = SHT2x(); } void Plant::init(void) @@ -30,10 +33,6 @@ void Plant::init(void) this->mSetting->pSensorDry->setValidator([](long candidate) { return (((candidate >= 0.0) && (candidate <= 100.0)) || equalish(candidate, DEACTIVATED_PLANT) || equalish(candidate, HYDROPONIC_MODE)); }); - this->mSetting->pSensorMode->setDefaultValue(NONE); - this->mSetting->pSensorMode->setValidator([](long candidate) - { return candidate == NONE || candidate == CAPACITIVE_FREQUENCY || candidate == ANALOG_RESISTANCE_PROBE; }); - this->mSetting->pPumpAllowedHourRangeStart->setDefaultValue(8); // start at 8:00 this->mSetting->pPumpAllowedHourRangeStart->setValidator([](long candidate) { return ((candidate >= 0) && (candidate <= 23)); }); @@ -56,18 +55,14 @@ void Plant::init(void) { return ((candidate >= 0) && (candidate <= 100)); }); /* Initialize Hardware */ - Serial.println("Init PWM controller for pump " + String(mPinPump) + "=" + String(OUTPUT)); - Serial.flush(); ledcSetup(this->mPlantId, PWM_FREQ, PWM_BITS); ledcAttachPin(mPinPump, this->mPlantId); ledcWrite(this->mPlantId, 0); - - Serial.println("Set GPIO mode " + String(mPinSensor) + "=" + String(ANALOG)); - Serial.flush(); pinMode(this->mPinSensor, INPUT); } -void Plant::initSensors(void){ +void Plant::initSensors(void) +{ switch (getSensorMode()) { case CAPACITIVE_FREQUENCY: @@ -89,19 +84,17 @@ void Plant::initSensors(void){ pcnt_counter_pause(unit); // Pausa o contador PCNT pcnt_counter_clear(unit); // Zera o contador PCNT - - Serial.println("Setup Counter " + String(mPinPump) + "=" + String(LOW)); break; } - case ANALOG_RESISTANCE_PROBE: { adcAttachPin(this->mPinSensor); break; } + case SHT20: case NONE: { - //do nothing + // do nothing break; } } @@ -117,13 +110,41 @@ void Plant::blockingMoistureMeasurement(void) { this->mMoisture_raw.add(analogReadMilliVolts(this->mPinSensor)); delay(5); - break; } + 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: { - //nothing to do here + // nothing to do here break; } } @@ -139,10 +160,11 @@ void Plant::startMoistureMeasurement(void) pcnt_counter_resume(unit); break; } + case SHT20: case ANALOG_RESISTANCE_PROBE: case NONE: { - //do nothing here + // do nothing here } } } @@ -170,11 +192,8 @@ void Plant::stopMoistureMeasurement(void) } break; } + case SHT20: case ANALOG_RESISTANCE_PROBE: - { - //nothing to do here - break; - } case NONE: { break; @@ -280,4 +299,5 @@ void Plant::advertise(void) this->mPlant->advertise("moist").setName("Percent").setDatatype("Float").setUnit("%"); this->mPlant->advertise("moistraw").setName("adc").setDatatype("Float").setUnit("3.3/4096V"); this->mPlant->advertise("state").setName("state").setDatatype("String"); + } diff --git a/esp32/src/main.cpp b/esp32/src/main.cpp index 45f21e3..be66d78 100644 --- a/esp32/src/main.cpp +++ b/esp32/src/main.cpp @@ -93,13 +93,13 @@ DS2438 battery(&oneWire, 0.0333333f, AMOUNT_SENOR_QUERYS); VL53L0X tankSensor; Plant mPlants[MAX_PLANTS] = { - Plant(SENSOR_PLANT0, OUTPUT_PUMP0, 0, &plant0, &mSetting0), - Plant(SENSOR_PLANT1, OUTPUT_PUMP1, 1, &plant1, &mSetting1), - Plant(SENSOR_PLANT2, OUTPUT_PUMP2, 2, &plant2, &mSetting2), - Plant(SENSOR_PLANT3, OUTPUT_PUMP3, 3, &plant3, &mSetting3), - Plant(SENSOR_PLANT4, OUTPUT_PUMP4, 4, &plant4, &mSetting4), - Plant(SENSOR_PLANT5, OUTPUT_PUMP5, 5, &plant5, &mSetting5), - Plant(SENSOR_PLANT6, OUTPUT_PUMP6, 6, &plant6, &mSetting6)}; + Plant(SENSOR_PLANT0, OUTPUT_PUMP0, 0, &plant0, &mSetting0, SHT20), + Plant(SENSOR_PLANT1, OUTPUT_PUMP1, 1, &plant1, &mSetting1, ANALOG_RESISTANCE_PROBE), + Plant(SENSOR_PLANT2, OUTPUT_PUMP2, 2, &plant2, &mSetting2, CAPACITIVE_FREQUENCY), + Plant(SENSOR_PLANT3, OUTPUT_PUMP3, 3, &plant3, &mSetting3, CAPACITIVE_FREQUENCY), + Plant(SENSOR_PLANT4, OUTPUT_PUMP4, 4, &plant4, &mSetting4, CAPACITIVE_FREQUENCY), + Plant(SENSOR_PLANT5, OUTPUT_PUMP5, 5, &plant5, &mSetting5, CAPACITIVE_FREQUENCY), + Plant(SENSOR_PLANT6, OUTPUT_PUMP6, 6, &plant6, &mSetting6, CAPACITIVE_FREQUENCY)}; /****************************************************************************** * LOCAL FUNCTIONS @@ -264,7 +264,6 @@ void readPowerSwitchedSensors() { mPlants[i].startMoistureMeasurement(); } - delay(MOISTURE_MEASUREMENT_DURATION); for (int i = 0; i < MAX_PLANTS; i++) { @@ -286,18 +285,26 @@ void readPowerSwitchedSensors() break; } case ANALOG_RESISTANCE_PROBE : { - Serial << "Plant " << i << " measurement: " << mPlants[i].getCurrentMoistureRaw() << " mV" << mPlants[i].getCurrentMoisturePCT() << "%" << endl; + 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 : { } } } - waterRawSensor.clear(); - Wire.setPins(SENSOR_TANK_TRG, SENSOR_TANK_ECHO); + //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(); bool distanceReady = false; @@ -761,13 +768,17 @@ void safeSetup() Homie.setLoopFunction(homieLoop); Homie.onEvent(onHomieEvent); - Homie.setup(); - - /* Intialize Plant */ + /* Intialize Plant */ for (int i = 0; i < MAX_PLANTS; i++) { mPlants[i].initSensors(); } + readPowerSwitchedSensors(); + + + Homie.setup(); + + /************************* Start One-Wire bus ***************/ int tempInitStartTime = millis(); @@ -794,14 +805,13 @@ void safeSetup() mConfigured = Homie.isConfigured(); if (mConfigured) { - Serial << "Reading sensors start" << endl; - Serial.flush(); - readPowerSwitchedSensors(); - Serial << "Reading sensors end" << endl; - Serial.flush(); 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);