Glitch protection with temperature sensor

I’ll start with the fact that I’m not a programmer and this is my first project. I’m trying to make a controller for a GrowBox or greenhouse.
At the moment, this code works and the whole project works. But recently there was a problem: from the temperature sensor si7021 stopped receiving temperature data and the heater worked constantly. How to write code to avoid such errors and the heater turned off when incorrect data from the sensor?
Code below, please do not kick I am not a professional.
The project is running on WeMos D1 R2 and uses a local blynk server running on Rpi2

/* Comment this out to disable prints and save space */
#define BLYNK_PRINT Serial
#define SENSOR A0  //подключение датчика влажности

#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <TimeLib.h>
#include <WidgetRTC.h>
#include "Adafruit_Si7021.h"
Adafruit_Si7021 sensor = Adafruit_Si7021();
//#include <Servo.h>
//Servo servo;
// Include the libraries we need
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Wire.h>

// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS D3

// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature sensors(&oneWire);

// arrays to hold device address
DeviceAddress insideThermometer;
WidgetRTC rtc;
// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
//char auth[] = "";
char auth[] = ""; //test

// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "Rt-ru";
char pass[] = "qazwsxedcrfv";

WidgetLED led1(V6); //индикатор обогрева
WidgetLED led2(V9); //индикатор освещения
WidgetLED led3(V8); //индикатор вытяжки
WidgetLED led4(V12); //индикатор испарителя
WidgetLED led5(V21); //индикатор обдува

long startTimeInSecs = 18000;//время включения освещения "Утро", до изменения в приложении
long stopTimeInSecs = 82800;//время выключения освещения "Вечер", до изменения в приложении
long tim; //вычисление текущего времени
//температура включения и выключения отопления по умолчанию
int TempHeatOffDay=33;//температура выключения обогрева днём
int TempHeatOffNight=25;//температура выключения обогрева ночью
int TempHeatOff; 
//влажность включения и выключения вытяжки по умолчанию
int humMax;//Влажность максимум
int humMin;//Влажность минимум
//состояние вентиляции
//int servoValue;
int buttonState; //состояние кнопки
int ventState; //состояние вентиляции
float sensorHumidity; //влажность с сенсора
float sensorTemp; //температура с сенсора
int wifisignal; //мощность wifi сигнала
int humGround; //влажность почвы
long startWateringTimeInSecs; //Время начала полива
int TimeWatering; //длительность полива

  BLYNK_WRITE(V3) { //ввод температуры дневной, старт обогрева
  TempHeatOffDay = param.asInt();
  Serial.print("Температура выключения обогрева день: ");
  Serial.println(TempHeatOffDay);
  }
  BLYNK_WRITE(V4) { //ввод температуры ночной, старт обогрева
  TempHeatOffNight = param.asInt();
  Serial.print("Температура выключения обогрева ночь: ");
  Serial.println(TempHeatOffNight);
  }
  BLYNK_WRITE(V7) { //ввод времени старта и окончания освещения
  startTimeInSecs = param[0].asLong();  // this would result in startTimeInSecs = 0
  stopTimeInSecs = param[1].asLong();   // this would result in endTimeInSecs = 3600
  }
  BLYNK_WRITE(V10) { //ввод минимальной влажности
  humMin = param.asInt(); // assigning incoming value from pin V1 to a variable
  Serial.print("Влажность минимальная: ");
  Serial.println(humMin);
  if (humMin >= humMax) {
    humMax = humMin+10;
    Blynk.virtualWrite(V11, humMax);
    }
  }
  BLYNK_WRITE(V11) { //ввод максимальной влажности
  humMax = param.asInt(); // assigning incoming value from pin V1 to a variable
  Serial.print("Влажность максимальная: ");
  Serial.println(humMax);
    if (humMax <= humMin) {
    humMin = humMax-10;
    Blynk.virtualWrite(V10, humMin);
    }
  }
  BLYNK_WRITE(V15) {
    if (param.asInt() == 0) {
      digitalWrite(D7, LOW);
      Serial.println("Вентиляция выключена");
    }
    else {
      digitalWrite(D7, HIGH);  
      Serial.println("вентиляция включена");
    }
  }
  BLYNK_WRITE(V20) {
    if (param.asInt() == 0) {
      Serial.println("Обдув выключен");
      digitalWrite(D4,LOW);
      led5.off();
    }
    else {
    Serial.println("Обдув включен");
      digitalWrite(D4,HIGH);
      led5.on();
    }
  }
  BLYNK_WRITE(V22) { //ввод времени старта и окончания освещения
    startWateringTimeInSecs = param[0].asLong();  // this would result in startTimeInSecs = 0
    Serial.println(startWateringTimeInSecs);
  }
  BLYNK_WRITE(V23) { //ввод максимальной влажности
    TimeWatering = param.asInt()* 60; // assigning incoming value from pin V1 to a variable
    Serial.println(TimeWatering);
  }

BlynkTimer timer;

void sendWifi()
{
  wifisignal = map(WiFi.RSSI(), -105, -40, 0, 100);
  Blynk.virtualWrite(V16, wifisignal);
}
void timerWatering() {
  long stopWateringTimeInSec = startWateringTimeInSecs + TimeWatering;
  if (tim >= startWateringTimeInSecs && tim <= stopWateringTimeInSec){
    digitalWrite(D0,HIGH);
    Serial.println("полив активирован");
  }
  else {
    digitalWrite(D0,LOW);
    Serial.println("полив выключен");
  }
}
void timerSvet() {
  sensorHumidity = sensor.readHumidity(); //влажность с si7021
  Blynk.virtualWrite(V2, sensorHumidity); 
  tim = (hour() * 3600 + minute() * 60); //вычисляем текущее время в секундах
  if (tim >= startTimeInSecs && tim <= stopTimeInSecs) //
    {
    digitalWrite(D6,HIGH);
    Serial.print("Свет включен");
    Serial.println();
    led2.on();
    TempHeatOff=TempHeatOffDay;   
  //испаритель включается и выключается только в дневное время
        if (sensorHumidity < humMin) {
          digitalWrite(D8,HIGH); //включение испарителя
          Serial.print("испаритель вкл");
          Serial.println();
          led4.on();
          Blynk.setProperty(V12, "color", "#00979D");
        }
        if (sensorHumidity > humMax) {
          digitalWrite(D8,LOW); //выключение испарителя
          Serial.print("испаритель выкл");
          Serial.println();
          led4.on();
          Blynk.setProperty(V12, "color", "#D3435C");
        }
     }
  else {
    digitalWrite(D6,LOW);
    Serial.println("Свет выключен");
    Serial.println("Испаритель выключен");
    led2.off();
    TempHeatOff=TempHeatOffNight;
    digitalWrite(D8,LOW); //выключение испарителя на ночь
  }
}

// This function sends Arduino's up time every second to Virtual Pin (5).
// In the app, Widget's reading frequency should be set to PUSH. This means
// that you define how often to send data to Blynk App.
void heating()
{
  sensorTemp = sensor.readTemperature(); //температура с si7021
// You can send any value at any time.
// Please don't send more that 10 values per second.
  Blynk.virtualWrite(V1, sensorTemp);
  if (sensorTemp > TempHeatOff)
  {
    digitalWrite(D5,LOW);
    Serial.println("Обогрев выключен");
    Serial.println(TempHeatOff);
    led1.off();
  }
  else {
    digitalWrite(D5,HIGH);
    Serial.print("Обогрев включен");
    Serial.println(TempHeatOff);
    led1.on();    
  }
}
void tempVnesh() {
  sensors.requestTemperatures(); // запрос температуры с 18d20
  float tempC = sensors.getTempCByIndex(0); // запрос температуры с 18d20
  Blynk.virtualWrite(V0, tempC);
}
void water() {
  uint16_t sensor = analogRead(SENSOR);
  humGround = map(sensor, 630, 330, 0, 100);
  Serial.println("влажность почвы");
  Serial.println(humGround);
  Blynk.virtualWrite(V18, humGround);
  }
  
  BLYNK_WRITE(V17)  // Reset
  {
    if (param.asInt()==1) {
    timer.setTimeout(2000, reset_esp);  
    } 
  }
void reset_esp()
{
  delay(3000);
  ESP.restart();
  delay(5000);
}

void setup()
{
// Debug console
Serial.begin(9600);

//Blynk.begin(auth, ssid, pass);
// You can also specify server:
Blynk.begin(auth, ssid, pass, "farahome.zzux.com", 8081);
//Blynk.begin(auth, ssid, pass, IPAddress(192,168,1,231), 8080);
//Blynk.begin(auth, ssid, pass, IPAddress(149,154,114,250), 8081);
Blynk.syncAll();

// Setup a function to be called every second
timer.setInterval(1000L, heating);
timer.setInterval(5060L, tempVnesh);
timer.setInterval(5120L, timerSvet);
timer.setInterval(10180L, sendWifi);
timer.setInterval(5240L, water);
timer.setInterval(5300L, timerWatering);
//timer.setInterval(5000L, clockDisplay);
sensor.begin();
pinMode(D0, OUTPUT); //полив
pinMode(D4, OUTPUT); //обдув
pinMode(D5, OUTPUT); //обогрев
pinMode(D6, OUTPUT); //освещение
pinMode(D7, OUTPUT); //вентиляция
pinMode(D8, OUTPUT); //испаритель
led1.off();
led2.off();
led3.off();
led4.off(); //испаритель
led5.off(); //обдув
rtc.begin();
sensors.begin();
//servo.attach(D0);
digitalWrite(D8,HIGH); //начальное включение испарителя
}

void loop()
{
Blynk.run();
timer.run(); // Initiates BlynkTimer
}

What kind of “incorrect data” were you getting from the sensor?

Pete.

this happened once, but it was enough that the temperature rose to 52 degrees Celsius and all the plants died. At that time, I was far from the greenhouse and in the application I have a temperature sensor is simply absent. The application itself worked and the temperature from another sensor showed correctly. I in the application on the phone sent the system to reboot and everything worked. So I don’t know what data the sensor was giving at this point. But I think that it was equivalent to the loss of power on the sensor.

It appears you have more then 1 temperature sensor. So you could use both of these to perform the temperature check that controls the heater. That is, both need to be below the threshold to turn the heater on.

Or you could periodically check to see if the temperature has changed. If the temperature remains constant for a given interval it could indicate that the senor has stopped working, and therefore you need to turn off the heater.

1 Like

You are right 2 temperature sensors. But si7021 is used to get temperature and humidity data inside the growbox. And the DS18B20 sensor to detect the outside temperature because the growbox is in an unheated room.
the question is how to write a program based on the fact that the power supply of the temperature sensor can be lost.
the system works 24/7 for the seventh month, and the problem occurred only once.

I would go with the second approach I mentioned. Check to see if the temperature is changing. If the heater is on, and the temperature is not changing, then something must be wrong.

I suggest you check if the sensor is working or not (value != NAN) before turn heat ON. If sensor not OK, turn heat OFF and send Blynk notification to the APP.
Test something similar to this code:

// This function sends Arduino's up time every second to Virtual Pin (5).
// In the app, Widget's reading frequency should be set to PUSH. This means
// that you define how often to send data to Blynk App.
void heating()
{
	static float t;
	static bool notificationSent = false;
	
	t = sensor.readTemperature(); //температура с si7021
	
	// Sensor will show 0 or whatever value you put here if sensor isn't working
  sensorTemp = 0;
  
  // Check if sensor is working
  if (!isnan(t))
	{
		sensorTemp = t;
		
		// You can send any value at any time.
		// Please don't send more that 10 values per second.
		if (sensorTemp > TempHeatOff)
		{
		  digitalWrite(D5,LOW);
		  Serial.println("Обогрев выключен");
		  Serial.println(TempHeatOff);
		  led1.off();
		}
		else {
		  digitalWrite(D5,HIGH);
		  Serial.print("Обогрев включен");
		  Serial.println(TempHeatOff);
		  led1.on();    
		}
  }
  else
  {
  	// Stop heat if sensor is not working
  	digitalWrite(D5,LOW);
  	if (!notificationSent)
  	{
  		notificationSent = true;
			// Send Blynk notification once that sensor isn't working. To include Blynk notification widget in app
			Blynk.notify("Si7021 sensor BAD");
	}
  }
  
  // Will show 0 if sensor isn't working
  Blynk.virtualWrite(V1, sensorTemp);
}

Good luck.

1 Like

i also use running median to get temp reading to compare to previous ones.

it helps smooth the readings and gets rid of one or two bad readings.

https://playground.arduino.cc/Main/RunningMedian/

1 Like

I think the long term key to this is going to be to work out what values you’re getting when the sensor is faulty.
Some sensors return -128° when they are in a fault state, and I guess that a zero could be returned is some circumstances.
I think the earlier advice to disregard values that are not a number (NAN) is a good approach.

I think I’d take readings less frequently than once per second, and write those values to a Blynk virtual pin and plot them on a SuperChart. However, as SuperChart averages the values received over a one minute period, an infrequent value may produce a slight glitch, but it won’t be easy to work-out exactly what value is being returned unless the same value is sent for every reading taken during a one minute period.

Two sensors in the same location would help, but careful coding would be needed because simply averaging the values, or only taking the higher reading may not fully solve the issue.

Pete.

this is a great method to prevent disastrous outcomes.

but you need an independent sensor to be the ‘watchman’ if the method is truly ‘failsafe’

1 Like