allow sensor type selection per plant, changed calculations to use PCT values, due to different raw value meaning

This commit is contained in:
c3ma
2022-02-12 05:26:54 +01:00
parent 7a54065a5f
commit d0320beaa7
9 changed files with 217 additions and 108 deletions

View File

@@ -4,4 +4,9 @@
bool equalish(double x, double y)
{
return (abs(x - y) < 0.5);
}
}
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;
}

View File

@@ -9,18 +9,11 @@
*
*/
#include "PlantCtrl.h"
#include "ControllerConfiguration.h"
#include "TimeUtils.h"
#include "MathUtils.h"
#include "driver/pcnt.h"
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;
}
Plant::Plant(int pinSensor, int pinPump, int plantId, HomieNode *plant, PlantSettings_t *setting)
{
this->mPinSensor = pinSensor;
@@ -37,6 +30,12 @@ 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(SENSOR_NONE);
this->mSetting->pSensorMode->setValidator([](long candidate) {
return candidate == SENSOR_NONE || candidate == SENSOR_CAPACITIVE_FREQUENCY_MOD || candidate == SENSOR_ANALOG_RESISTANCE_PROBE;
});
this->mSetting->pPumpAllowedHourRangeStart->setDefaultValue(8); // start at 8:00
this->mSetting->pPumpAllowedHourRangeStart->setValidator([](long candidate) {
return ((candidate >= 0) && (candidate <= 23));
@@ -76,47 +75,82 @@ void Plant::init(void)
Serial.flush();
pinMode(this->mPinSensor, INPUT);
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
if(isSensorMode(SENSOR_CAPACITIVE_FREQUENCY_MOD)){
pcnt_counter_pause(unit); // Pausa o contador PCNT
pcnt_counter_clear(unit); // Zera o contador PCNT
pcnt_unit_t unit = (pcnt_unit_t) (PCNT_UNIT_0 + this->mPlantId);
pcnt_config_t pcnt_config = { }; // Instancia PCNT config
Serial.println("Setup Counter " + String(mPinPump) + "=" + String(LOW));
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));
} else if (isSensorMode(SENSOR_ANALOG_RESISTANCE_PROBE)){
adcAttachPin(this->mPinSensor);
} else if (isSensorMode(SENSOR_NONE)){
//nothing to do here
} else {
log(LOG_LEVEL_ERROR, LOG_SENSORMODE_UNKNOWN, LOG_SENSORMODE_UNKNOWN_CODE);
}
}
void Plant::blockingMoistureMeasurement(void) {
if(isSensorMode(SENSOR_ANALOG_RESISTANCE_PROBE)){
for(int i = 0;i<ANALOG_REREADS;i++){
this->mMoisture_raw.add(analogReadMilliVolts(this->mPinSensor));
delay(5);
}
}else if(isSensorMode(SENSOR_CAPACITIVE_FREQUENCY_MOD) || isSensorMode(SENSOR_NONE)){
//nothing to do here
} else {
log(LOG_LEVEL_ERROR, LOG_SENSORMODE_UNKNOWN, LOG_SENSORMODE_UNKNOWN_CODE);
}
}
void Plant::startMoistureMeasurement(void) {
pcnt_unit_t unit = (pcnt_unit_t) (PCNT_UNIT_0 + this->mPlantId);
pcnt_counter_resume(unit);
if(isSensorMode(SENSOR_CAPACITIVE_FREQUENCY_MOD)){
pcnt_unit_t unit = (pcnt_unit_t) (PCNT_UNIT_0 + this->mPlantId);
pcnt_counter_resume(unit);
} else if (isSensorMode(SENSOR_ANALOG_RESISTANCE_PROBE) || isSensorMode(SENSOR_NONE)){
//nothing to do here
} else {
log(LOG_LEVEL_ERROR, LOG_SENSORMODE_UNKNOWN, LOG_SENSORMODE_UNKNOWN_CODE);
}
}
void Plant::stopMoistureMeasurement(void) {
int16_t pulses;
pcnt_unit_t unit = (pcnt_unit_t) (PCNT_UNIT_0 + this->mPlantId);
pcnt_counter_pause(unit);
esp_err_t result = pcnt_get_counter_value(unit, &pulses);
pcnt_counter_clear(unit);
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);
if(isSensorMode(SENSOR_CAPACITIVE_FREQUENCY_MOD)){
int16_t pulses;
pcnt_unit_t unit = (pcnt_unit_t) (PCNT_UNIT_0 + this->mPlantId);
pcnt_counter_pause(unit);
esp_err_t result = pcnt_get_counter_value(unit, &pulses);
pcnt_counter_clear(unit);
if(result != ESP_OK){
log(LOG_LEVEL_ERROR, LOG_HARDWARECOUNTER_ERROR_MESSAGE, LOG_HARDWARECOUNTER_ERROR_CODE);
this-> mMoisture_raw.clear();
this -> mMoisture_raw.add(-1);
} else {
this->mMoisture_raw.add(pulses * (1000 / MOISTURE_MEASUREMENT_DURATION));
}
}else if (isSensorMode(SENSOR_ANALOG_RESISTANCE_PROBE) || isSensorMode(SENSOR_NONE)){
//nothing to do here
} else {
log(LOG_LEVEL_ERROR, LOG_SENSORMODE_UNKNOWN, LOG_SENSORMODE_UNKNOWN_CODE);
}
}
void Plant::postMQTTconnection(void)
@@ -125,8 +159,10 @@ void Plant::postMQTTconnection(void)
this->mConnected = true;
this->mPlant->setProperty("switch").send(OFF);
long raw = getCurrentMoisture();
double pct = mapf(raw, MOIST_SENSOR_MIN_FRQ, MOIST_SENSOR_MAX_FRQ, 100, 0);
float pct = getCurrentMoisturePCT();
float raw = getCurrentMoistureRaw();
Serial.println(pct);
Serial.println("..................");
if (equalish(raw, MISSING_SENSOR))
{
pct = 0;
@@ -140,9 +176,9 @@ void Plant::postMQTTconnection(void)
pct = 100;
}
this->mPlant->setProperty("moist").send(String(round(pct*10)/10));
this->mPlant->setProperty("moist").send(String(pct));
this->mPlant->setProperty("moistraw").send(String(raw));
this->mPlant->setProperty("moisttrigger").send(String(getSetting2Moisture()));
this->mPlant->setProperty("moisttrigger").send(String(getTargetMoisturePCT()));
}
void Plant::deactivatePump(void)

View File

@@ -209,7 +209,7 @@ void readOneWireSensors()
continue;
}
char buf[(sizeof(ds18b20Address) * 2)+1]; /* additional byte for trailing terminator */
char buf[(sizeof(ds18b20Address) * 2) + 1]; /* additional byte for trailing terminator */
snprintf(buf, sizeof(buf), "%.2X%.2X%.2X%.2X%.2X%.2X%.2X%.2X",
ds18b20Address[0],
ds18b20Address[1],
@@ -269,7 +269,27 @@ void readPowerSwitchedSensors()
for (int i = 0; i < MAX_PLANTS; i++)
{
Serial << "Plant " << i << " measurement: " << mPlants[i].getCurrentMoisture() << " hz" << endl;
mPlants[i].blockingMoistureMeasurement();
}
for (int i = 0; i < MAX_PLANTS; i++)
{
if (mPlants[i].isSensorMode(SENSOR_CAPACITIVE_FREQUENCY_MOD))
{
Serial << "Plant " << i << " measurement: " << mPlants[i].getCurrentMoistureRaw() << " hz" << endl;
}
else if (mPlants[i].isSensorMode(SENSOR_ANALOG_RESISTANCE_PROBE))
{
Serial << "Plant " << i << " measurement: " << mPlants[i].getCurrentMoistureRaw() << " mV" << endl;
}
else if (mPlants[i].isSensorMode(SENSOR_NONE))
{
Serial << "Plant " << i << " measurement: no sensor configured" << endl;
}
else
{
log(LOG_LEVEL_ERROR, LOG_SENSORMODE_UNKNOWN, LOG_SENSORMODE_UNKNOWN_CODE);
}
}
waterRawSensor.clear();
@@ -408,7 +428,7 @@ int determineNextPump(bool isLowLight)
}
if (!plant.isHydroponic())
{
if (equalish(plant.getCurrentMoisture(), MISSING_SENSOR))
if (equalish(plant.getCurrentMoistureRaw(), MISSING_SENSOR))
{
plant.publishState("nosensor");
log(LOG_LEVEL_ERROR, String(String(i) + " No pump possible: missing sensor"), LOG_MISSING_PUMP);
@@ -631,7 +651,7 @@ void pumpActiveLoop()
#endif
long pumpStarted = pumpTarget - (mPlants[pumpToRun].getPumpDuration() * 1000);
long duration = millis()-pumpStarted;
long duration = millis() - pumpStarted;
if (millis() > pumpTarget)
{
mPlants[pumpToRun].setProperty("watertime").send(String(duration));
@@ -704,33 +724,7 @@ void safeSetup()
return;
}
/************************* Start One-Wire bus ***************/
int tempInitStartTime = millis();
uint8_t sensorCount = 0U;
/* Required to read the temperature at least once */
while ((sensorCount == 0 || !battery.isFound()) && millis() < tempInitStartTime + TEMPERATUR_TIMEOUT)
{
sensors.begin();
battery.begin();
sensorCount = sensors.getDS18Count();
delay(50);
}
Serial << "DS18S20 count: " << sensorCount << " found in " << (millis() - tempInitStartTime) << " ms" << endl;
Serial.flush();
/* Measure temperature TODO idea: move this into setup */
if (sensorCount > 0)
{
//sensors.setResolution(DS18B20_RESOLUTION);
sensors.requestTemperatures();
}
Serial << "Reading sensors start" << endl;
Serial.flush();
readPowerSwitchedSensors();
Serial << "Reading sensors end" << endl;
Serial.flush();
/************************* Start Homie Framework ***************/
/************************* Start Homie Framework ***************/
Homie_setFirmware("PlantControl", FIRMWARE_VERSION);
Homie.disableLedFeedback();
Homie_setBrand("PlantControl");
@@ -766,9 +760,36 @@ void safeSetup()
Homie.setup();
/************************* Start One-Wire bus ***************/
int tempInitStartTime = millis();
uint8_t sensorCount = 0U;
/* Required to read the temperature at least once */
while ((sensorCount == 0 || !battery.isFound()) && millis() < tempInitStartTime + TEMPERATUR_TIMEOUT)
{
sensors.begin();
battery.begin();
sensorCount = sensors.getDS18Count();
delay(50);
}
Serial << "DS18S20 count: " << sensorCount << " found in " << (millis() - tempInitStartTime) << " ms" << endl;
Serial.flush();
/* Measure temperature TODO idea: move this into setup */
if (sensorCount > 0)
{
//sensors.setResolution(DS18B20_RESOLUTION);
sensors.requestTemperatures();
}
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();