2020-09-07 18:18:46 +02:00
|
|
|
/**
|
|
|
|
* @file PlantCtrl.cpp
|
|
|
|
* @author your name (you@domain.com)
|
|
|
|
* @brief
|
|
|
|
* @version 0.1
|
|
|
|
* @date 2020-05-27
|
|
|
|
*
|
|
|
|
* @copyright Copyright (c) 2020
|
|
|
|
*
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "PlantCtrl.h"
|
2020-11-04 23:28:08 +01:00
|
|
|
#include "ControllerConfiguration.h"
|
2021-07-01 21:19:51 +02:00
|
|
|
#include "TimeUtils.h"
|
2021-07-09 21:50:51 +02:00
|
|
|
#include "MathUtils.h"
|
2021-07-21 21:23:58 +02:00
|
|
|
#include "driver/pcnt.h"
|
2021-07-09 21:50:51 +02:00
|
|
|
|
|
|
|
double mapf(double x, double in_min, double in_max, double out_min, double out_max)
|
|
|
|
{
|
|
|
|
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
|
|
|
}
|
2020-09-07 18:18:46 +02:00
|
|
|
|
2020-11-04 21:57:40 +01:00
|
|
|
Plant::Plant(int pinSensor, int pinPump, int plantId, HomieNode *plant, PlantSettings_t *setting)
|
|
|
|
{
|
2020-10-14 20:07:56 +02:00
|
|
|
this->mPinSensor = pinSensor;
|
|
|
|
this->mPinPump = pinPump;
|
2020-10-16 16:22:48 +02:00
|
|
|
this->mPlant = plant;
|
2020-11-04 21:57:40 +01:00
|
|
|
this->mSetting = setting;
|
2020-12-20 17:00:44 +01:00
|
|
|
this->mPlantId = plantId;
|
2020-10-16 18:25:02 +02:00
|
|
|
}
|
|
|
|
|
2020-11-04 21:57:40 +01:00
|
|
|
void Plant::init(void)
|
|
|
|
{
|
2020-10-23 16:20:34 +02:00
|
|
|
/* Initialize Home Settings validator */
|
2020-10-28 21:20:46 +01:00
|
|
|
this->mSetting->pSensorDry->setDefaultValue(DEACTIVATED_PLANT);
|
2021-10-26 20:46:40 +02:00
|
|
|
this->mSetting->pSensorDry->setValidator([](long candidate) {
|
|
|
|
return (((candidate >= 0.0) && (candidate <= 100.0)) || equalish(candidate,DEACTIVATED_PLANT) || equalish(candidate,HYDROPONIC_MODE));
|
2020-10-16 16:22:48 +02:00
|
|
|
});
|
2020-10-16 18:40:39 +02:00
|
|
|
this->mSetting->pPumpAllowedHourRangeStart->setDefaultValue(8); // start at 8:00
|
2020-11-04 21:57:40 +01:00
|
|
|
this->mSetting->pPumpAllowedHourRangeStart->setValidator([](long candidate) {
|
|
|
|
return ((candidate >= 0) && (candidate <= 23));
|
2020-10-16 16:22:48 +02:00
|
|
|
});
|
2020-10-16 18:40:39 +02:00
|
|
|
this->mSetting->pPumpAllowedHourRangeEnd->setDefaultValue(20); // stop pumps at 20:00
|
2020-11-04 21:57:40 +01:00
|
|
|
this->mSetting->pPumpAllowedHourRangeEnd->setValidator([](long candidate) {
|
|
|
|
return ((candidate >= 0) && (candidate <= 23));
|
2020-10-16 16:22:48 +02:00
|
|
|
});
|
2020-10-16 18:25:02 +02:00
|
|
|
this->mSetting->pPumpOnlyWhenLowLight->setDefaultValue(true);
|
2021-10-22 19:39:42 +02:00
|
|
|
this->mSetting->pPumpCooldownInMinutes->setDefaultValue(20); // minutes
|
|
|
|
this->mSetting->pPumpCooldownInMinutes->setValidator([](long candidate) {
|
|
|
|
return ((candidate >= 0) && (candidate <= 60*24*7));
|
2020-10-16 16:22:48 +02:00
|
|
|
});
|
2020-10-23 16:20:34 +02:00
|
|
|
|
2021-10-01 23:46:37 +02:00
|
|
|
this->mSetting->pPumpDuration->setDefaultValue(5);
|
|
|
|
this->mSetting->pPumpDuration->setValidator([](long candidate) {
|
|
|
|
return ((candidate >= 0) && (candidate <= 1000));
|
|
|
|
});
|
2021-10-26 21:50:55 +02:00
|
|
|
this->mSetting->pPumpPowerLevel->setDefaultValue(100);
|
|
|
|
this->mSetting->pPumpPowerLevel->setValidator([](long candidate) {
|
|
|
|
return ((candidate >= 0) && (candidate <= 100));
|
|
|
|
});
|
2021-10-01 23:46:37 +02:00
|
|
|
|
|
|
|
|
2020-10-23 16:20:34 +02:00
|
|
|
/* Initialize Hardware */
|
2021-10-26 21:50:55 +02:00
|
|
|
Serial.println("Init PWM controller for pump " + String(mPinPump) + "=" + String(OUTPUT));
|
2021-05-24 14:58:35 +02:00
|
|
|
Serial.flush();
|
2021-10-26 21:50:55 +02:00
|
|
|
ledcSetup(this->mPlantId, PWM_FREQ, PWM_BITS);
|
|
|
|
ledcAttachPin(mPinPump, this->mPlantId);
|
|
|
|
ledcWrite(this->mPlantId, 0);
|
|
|
|
|
2021-05-24 14:58:35 +02:00
|
|
|
Serial.println("Set GPIO mode " + String(mPinSensor) + "=" + String(ANALOG));
|
|
|
|
Serial.flush();
|
2021-07-21 21:23:58 +02:00
|
|
|
pinMode(this->mPinSensor, INPUT);
|
2021-05-24 14:58:35 +02:00
|
|
|
Serial.println("Set GPIO " + String(mPinPump) + "=" + String(LOW));
|
|
|
|
Serial.flush();
|
2020-11-04 21:57:40 +01:00
|
|
|
digitalWrite(this->mPinPump, LOW);
|
2021-07-21 21:23:58 +02:00
|
|
|
pcnt_unit_t unit = (pcnt_unit_t) (PCNT_UNIT_0 + this->mPlantId);
|
|
|
|
pcnt_config_t pcnt_config = { }; // Instancia PCNT config
|
|
|
|
|
|
|
|
pcnt_config.pulse_gpio_num = this->mPinSensor; // Configura GPIO para entrada dos pulsos
|
|
|
|
pcnt_config.ctrl_gpio_num = PCNT_PIN_NOT_USED; // Configura GPIO para controle da contagem
|
|
|
|
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_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
|
|
|
|
|
|
|
|
|
|
|
|
pcnt_counter_pause(unit); // Pausa o contador PCNT
|
|
|
|
pcnt_counter_clear(unit); // Zera o contador PCNT
|
|
|
|
|
|
|
|
Serial.println("Setup Counter " + String(mPinPump) + "=" + String(LOW));
|
2020-10-23 16:20:34 +02:00
|
|
|
}
|
|
|
|
|
2021-07-21 21:23:58 +02:00
|
|
|
void Plant::startMoistureMeasurement(void) {
|
|
|
|
pcnt_unit_t unit = (pcnt_unit_t) (PCNT_UNIT_0 + this->mPlantId);
|
|
|
|
pcnt_counter_resume(unit);
|
2021-07-01 20:39:51 +02:00
|
|
|
}
|
|
|
|
|
2021-07-21 21:23:58 +02:00
|
|
|
void Plant::stopMoistureMeasurement(void) {
|
|
|
|
int16_t pulses;
|
|
|
|
pcnt_unit_t unit = (pcnt_unit_t) (PCNT_UNIT_0 + this->mPlantId);
|
|
|
|
pcnt_counter_pause(unit);
|
2021-10-06 21:24:34 +02:00
|
|
|
esp_err_t result = pcnt_get_counter_value(unit, &pulses);
|
2021-07-21 21:23:58 +02:00
|
|
|
pcnt_counter_clear(unit);
|
2021-10-06 21:24:34 +02:00
|
|
|
|
|
|
|
|
|
|
|
if(result != ESP_OK){
|
|
|
|
//FIXME log(LOG_LEVEL_ERROR, LOG_HARDWARECOUNTER_ERROR_MESSAGE, LOG_HARDWARECOUNTER_ERROR_CODE);
|
|
|
|
this -> mMoisture_freq = -1;
|
|
|
|
} else {
|
|
|
|
this->mMoisture_freq = pulses * (1000 / MOISTURE_MEASUREMENT_DURATION);
|
|
|
|
}
|
|
|
|
|
2020-10-23 16:20:34 +02:00
|
|
|
}
|
|
|
|
|
2020-11-04 21:57:40 +01:00
|
|
|
void Plant::postMQTTconnection(void)
|
|
|
|
{
|
2020-10-23 16:20:34 +02:00
|
|
|
const String OFF = String("OFF");
|
2020-11-04 21:57:40 +01:00
|
|
|
this->mConnected = true;
|
2020-10-23 16:20:34 +02:00
|
|
|
this->mPlant->setProperty("switch").send(OFF);
|
2021-07-09 21:50:51 +02:00
|
|
|
|
|
|
|
long raw = getCurrentMoisture();
|
2021-07-21 21:23:58 +02:00
|
|
|
double pct = mapf(raw, MOIST_SENSOR_MIN_FRQ, MOIST_SENSOR_MAX_FRQ, 100, 0);
|
2021-07-09 21:50:51 +02:00
|
|
|
if (equalish(raw, MISSING_SENSOR))
|
|
|
|
{
|
|
|
|
pct = 0;
|
|
|
|
}
|
|
|
|
if (pct < 0)
|
|
|
|
{
|
|
|
|
pct = 0;
|
|
|
|
}
|
|
|
|
if (pct > 100)
|
|
|
|
{
|
|
|
|
pct = 100;
|
|
|
|
}
|
|
|
|
|
|
|
|
this->mPlant->setProperty("moist").send(String(round(pct*10)/10));
|
|
|
|
this->mPlant->setProperty("moistraw").send(String(raw));
|
2021-08-17 16:55:52 +02:00
|
|
|
this->mPlant->setProperty("moisttrigger").send(String(getSetting2Moisture()));
|
2020-10-23 16:20:34 +02:00
|
|
|
}
|
|
|
|
|
2020-11-04 21:57:40 +01:00
|
|
|
void Plant::deactivatePump(void)
|
|
|
|
{
|
2021-05-26 21:46:33 +02:00
|
|
|
int plantId = this->mPlantId;
|
|
|
|
Serial << "deactivating pump " << plantId << endl;
|
2021-10-26 21:50:55 +02:00
|
|
|
ledcWrite(this->mPlantId, 0);
|
2020-11-04 21:57:40 +01:00
|
|
|
if (this->mConnected)
|
|
|
|
{
|
2020-10-23 16:20:34 +02:00
|
|
|
const String OFF = String("OFF");
|
|
|
|
this->mPlant->setProperty("switch").send(OFF);
|
|
|
|
}
|
2020-09-07 18:18:46 +02:00
|
|
|
}
|
|
|
|
|
2021-07-01 22:06:50 +02:00
|
|
|
void Plant::publishState(String state) {
|
|
|
|
if (this->mConnected)
|
|
|
|
{
|
|
|
|
this->mPlant->setProperty("state").send(state);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-04 21:57:40 +01:00
|
|
|
void Plant::activatePump(void)
|
|
|
|
{
|
2021-05-26 21:46:33 +02:00
|
|
|
int plantId = this->mPlantId;
|
2021-10-26 21:50:55 +02:00
|
|
|
|
2021-05-26 21:46:33 +02:00
|
|
|
Serial << "activating pump " << plantId << endl;
|
2021-10-26 21:50:55 +02:00
|
|
|
long desiredPowerLevelPercent = this->mSetting->pPumpPowerLevel->get();
|
|
|
|
ledcWrite(this->mPlantId, desiredPowerLevelPercent*PWM_BITS);
|
2020-11-04 21:57:40 +01:00
|
|
|
if (this->mConnected)
|
|
|
|
{
|
2020-10-23 16:20:34 +02:00
|
|
|
const String OFF = String("ON");
|
|
|
|
this->mPlant->setProperty("switch").send(OFF);
|
2021-07-01 21:19:51 +02:00
|
|
|
this->mPlant->setProperty("lastPump").send(String(getCurrentTime()));
|
2020-10-23 16:20:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-09 22:51:50 +02:00
|
|
|
bool Plant::switchHandler(const HomieRange& range, const String& value) {
|
|
|
|
if (range.isRange) {
|
|
|
|
return false; // only one switch is present
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((value.equals("ON")) || (value.equals("On")) || (value.equals("on")) || (value.equals("true"))) {
|
|
|
|
this->activatePump();
|
|
|
|
return true;
|
|
|
|
} else if ((value.equals("OFF")) || (value.equals("Off")) || (value.equals("off")) || (value.equals("false")) ) {
|
|
|
|
this->deactivatePump();
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Plant::setSwitchHandler(HomieInternals::PropertyInputHandler f) {
|
|
|
|
this->mPump.settable(f);
|
|
|
|
}
|
|
|
|
|
2020-11-04 21:57:40 +01:00
|
|
|
void Plant::advertise(void)
|
|
|
|
{
|
2020-10-23 16:20:34 +02:00
|
|
|
// Advertise topics
|
2021-07-09 22:51:50 +02:00
|
|
|
mPump = this->mPlant->advertise("switch").setName("Pump").setDatatype("boolean");
|
2021-07-14 21:43:03 +02:00
|
|
|
this->mPlant->advertise("lastPump").setName("lastPump").setDatatype("Number").setUnit("unixtime");
|
|
|
|
this->mPlant->advertise("moist").setName("Percent").setDatatype("Number").setUnit("%");
|
|
|
|
this->mPlant->advertise("moistraw").setName("adc").setDatatype("Number").setUnit("3.3/4096V");
|
2021-07-01 22:06:50 +02:00
|
|
|
this->mPlant->advertise("state").setName("state").setDatatype("string");
|
2020-10-23 16:20:34 +02:00
|
|
|
}
|