The hardware stops working

So, I guess that the problem hides in ENC28J60. I added external protection module and arduino reboot function, so now I’m protected :slight_smile: Thanks everyone who helped me with my project.

Hi. There is a new issue: in one moment (after one week of working), the hardware starts to leave offline always.
I gonna explain.
If the hardware goes offline, the device will be rebooted in 35 minutes. It starts to work like this: it comes online for a few seconds, sends the data several times, goes offline and comes back after 35 minutes.

#define MODE_EEPROM_INDEX 0
#define PUMP1_EEPROM_INDEX 1
#define PUMP2_EEPROM_INDEX 2
#define PERIOD_EEPROM_INDEX 3
#define RESET_DATA_EEPROM_INDEX 4

#include <UIPEthernet.h>
#include <BlynkSimpleUIPEthernet.h>

const char AUTH[] = "ba2024ad11874d1d8e73cfbcf9b1fde0"; // токен для ethernet

BlynkTimer temp_timer;
BlynkTimer online_signal_timer;
BlynkTimer protection_timer;
BlynkTimer set_all_timer;

#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS A5
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

DeviceAddress floor1_temp_sensor = {0x28, 0xFF, 0xCE, 0xD0, 0x01, 0x17, 0x05, 0xDF};
DeviceAddress floor2_temp_sensor = {0x28, 0xFF, 0x09, 0xD0, 0x01, 0x17, 0x05, 0xAC};
DeviceAddress podacha_temp_sensor = {0x28, 0x41, 0x0F, 0x43, 0x98, 0x18, 0x00, 0xCC};
DeviceAddress obratka_temp_sensor = {0x28, 0x57, 0x20, 0x43, 0x98, 0x25, 0x00, 0x16};
DeviceAddress radiator_temp_sensor = {0x28, 0xFF, 0xEC, 0xCE, 0x01, 0x17, 0x05, 0x89};

#define pump1 7
#define pump2 8
#define protection_pin_1 10
#define protection_pin_2 11
#define heater 12

#define radiator_temp_VP V0
#define temp1_VP V1
#define temp2_VP V2
#define podacha_temp_VP V3
#define obratka_temp_VP V4
#define delta_VP V5
#define mode_VP V6
#define heater_led_VP V7
#define online_led_VP V8
#define pump1_VP V9
#define pump2_VP V10
#define period_VP V11

WidgetLED heater_led(heater_led_VP);
WidgetLED online_led(online_led_VP);

const byte AVERAGE_FACTOR = 5;  // if 0 - don't average values
/* TIME_MULTIPLIER corrects the time counting
   60000 - in minutes
   1000 - in seconds
   1 - in millis
*/
const unsigned long TIME_MULTIPLIER = 60000;

unsigned long end_time;  // in millis
float radiator_temp;
float floor1_temp;
float floor2_temp;
float podacha_temp;
float obratka_temp;
byte period = 10;  //  heating period in minutes
byte mode;
byte heater_system_delta;
bool heater_state;
bool pump1_state;
bool pump2_state;

BLYNK_WRITE(pump1_VP)
{
  bool x = param.asInt(); // assigning incoming value from pin V1 to a variable
  pump1_state = x;
  EEPROM.update(PUMP1_EEPROM_INDEX, x);
}

BLYNK_WRITE(pump2_VP)
{
  bool x = param.asInt(); // assigning incoming value from pin V1 to a variable
  pump2_state = x;
  EEPROM.update(PUMP2_EEPROM_INDEX, x);
}

BLYNK_WRITE(delta_VP)
{
  byte delta = param.asInt();
  heater_system_delta = delta;
}

BLYNK_WRITE(mode_VP)
{
  byte new_mode = param.asInt();
  // for the case when in the start of program new_mode == mode
  if (mode != new_mode) {
    mode = new_mode;
    end_time = 0;  // for re-count in function
    heater_state = false;  // for restart it right now
    EEPROM.update(MODE_EEPROM_INDEX, new_mode);
  }
}

BLYNK_WRITE(period_VP)
{
  byte new_period = param.asInt();
  period = new_period;
  EEPROM.update(PERIOD_EEPROM_INDEX, new_period);
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  Serial.println("started");
  pinMode(protection_pin_1, OUTPUT);
  pinMode(protection_pin_2, OUTPUT);
  pinMode(heater, OUTPUT);
  pinMode(pump1, OUTPUT);
  pinMode(pump2, OUTPUT);

  sensors.begin();
  sensors.setResolution(radiator_temp_sensor, 11);
  sensors.setResolution(floor1_temp_sensor, 11);
  sensors.setResolution(floor2_temp_sensor, 11);
  sensors.setResolution(podacha_temp_sensor, 11);
  sensors.setResolution(obratka_temp_sensor, 11);
  sensors.setWaitForConversion(false); // make reading NON blocking
  sensors.requestTemperatures();       // start conversion for first reading

  setFromEEPROM();

  Blynk.begin(AUTH);
  if (EEPROM.read(RESET_DATA_EEPROM_INDEX)) {
    Blynk.notify("Тут сеть выпадала. Но я снова с вами!");
    EEPROM.update(RESET_DATA_EEPROM_INDEX, false);
  }
  else {
    Blynk.notify("Я включился! Видимо, не было электричества.");
  }
  Blynk.syncAll();
  set_all_timer.setInterval(1000L, setAll);
  temp_timer.setInterval(1500L, tempCheckerAndSender);
  protection_timer.setInterval(750L, protectionRoutine);
  online_signal_timer.setInterval(5000L, onlineSignalSender);
}

void loop() {
  Blynk.run();
  temp_timer.run();
  protection_timer.run();
  online_signal_timer.run();
  set_all_timer.run();
}

void setAll() {
  digitalWrite(pump1, pump1_state);
  digitalWrite(pump2, pump2_state);
  heaterController();  // for setting heater state using mode data
}

void tempCheckerAndSender() {
  floor1_temp = averageFilter(sensors.getTempC(floor1_temp_sensor), floor1_temp);
  floor2_temp = averageFilter(sensors.getTempC(floor2_temp_sensor), floor2_temp);
  podacha_temp = averageFilter(sensors.getTempC(podacha_temp_sensor), podacha_temp);
  obratka_temp = averageFilter(sensors.getTempC(obratka_temp_sensor), obratka_temp);
  radiator_temp = averageFilter(sensors.getTempC(radiator_temp_sensor), radiator_temp);
  sensors.requestTemperatures();
  Blynk.virtualWrite(temp1_VP, floor1_temp);
  Blynk.virtualWrite(temp2_VP, floor2_temp);
  Blynk.virtualWrite(podacha_temp_VP, podacha_temp);
  Blynk.virtualWrite(obratka_temp_VP, obratka_temp);
  Blynk.virtualWrite(radiator_temp_VP, radiator_temp);
}

void onlineSignalSender() {
  static bool parity;
  online_led.setValue(parity * 255);
  parity = !parity;
}

void(* resetFunc) (void) = 0;

void protectionRoutine() {
  byte pin;
  static bool parity;
  static bool reconnect;
  static unsigned long time_of_last_online;
  const unsigned long OFFLINE_IGNORE_PERIOD = 120000;  // in millis
  // if the hardware went offline
  if (!Blynk.connected()) {
    if (!reconnect) {
      reconnect = true;
      time_of_last_online = millis();
    }
    else if (millis() - time_of_last_online > 2100000) {
      // if there is no action for more than 10 minutes
      // soft reset routine
      EEPROM.update(RESET_DATA_EEPROM_INDEX, true);
      resetFunc();
    }
    else if (millis() - time_of_last_online > 1500000) {
      // leave the function because we don't need to send signals for reboot arduino
      EEPROM.update(RESET_DATA_EEPROM_INDEX, true);
      return;
    }
  }
  else {
    // if connected, stop the protection
    reconnect = false;
    EEPROM.update(RESET_DATA_EEPROM_INDEX, false);
    if (millis() - time_of_last_online > OFFLINE_IGNORE_PERIOD) {
      Blynk.notify("Тут сеть выпадала. Но я снова с вами!");
    }
    time_of_last_online = millis();
  }
  // if everything is OK, choose a pin to send the data
  if (parity) {
    pin = protection_pin_1;
  }
  else {
    pin = protection_pin_2;
  }
  // send short signal
  digitalWrite(pin, random(0, 2));  // send a random signal
  parity = !parity;
}

void heaterController() {
  static bool overheat;
  if (podacha_temp >= 90 and !overheat) {
    digitalWrite(heater, LOW);
    overheat = true;
    Blynk.notify("О-о, подача перегрелась. Но я отключил ТЭНы, не волнуйтесь. Когда температура будет меньше 82°, я все верну.");
    return;  //  leave the function
  }
  else if (overheat and podacha_temp >= 82) {
    return;
  }
  else if (overheat and podacha_temp < 82) {
    overheat = false;  //for continue working in normal mode
  }

  // the next code will be completed if the previous cases won't leave the function
  if (mode == 0) {
    heater_state = false;
  }
  else {
    unsigned long time_on = mode * TIME_MULTIPLIER;
    unsigned long time_off = (period * TIME_MULTIPLIER) - time_on;
    if (time_off == 0) {
      heater_state = true;
    }
    else {
      if (millis() > end_time) {
        heater_state = !heater_state;
        if (heater_state) {
          end_time = millis() + time_on;
        }
        else {
          end_time = millis() + time_off;
        }
      }
    }
  }

  static bool send_when_connect = false;  // it helps in case if the pump1_state changed automatically and button state in Blynk didn't changed
  if (heater_state and !pump1_state and !pump2_state) {
    pump1_state = true;
    EEPROM.update(PUMP1_EEPROM_INDEX, pump1_state);
    if (Blynk.connected()) {
      Blynk.virtualWrite(pump1_VP, pump1_state);
      Blynk.notify("Вы тут ошиблись и включили ТЭНы без насоса. Не волнуйтесь, я обо всем позаботился и включил насос первого этажа.");
    }
    else {
      send_when_connect = true;
    }
  }
  if (send_when_connect and Blynk.connected()) {
    send_when_connect = false;
    Blynk.virtualWrite(pump1_VP, pump1_state);
  }

  digitalWrite(heater, heater_state);
  heater_led.setValue(heater_state * 255);
}

float averageFilter (float new_val, float old_avg) {
  if (AVERAGE_FACTOR > 0) {
    return (old_avg * (AVERAGE_FACTOR - 1) + new_val) / AVERAGE_FACTOR;
  }
  else {
    return new_val;
  }
}

void setFromEEPROM() {
  mode = EEPROM.read(MODE_EEPROM_INDEX);
  // next code will save from overheat
  if (mode > 5) {
    mode = 3;
  }
  pump1_state = EEPROM.read(PUMP1_EEPROM_INDEX);
  pump2_state = EEPROM.read(PUMP2_EEPROM_INDEX);
  period = EEPROM.read(PERIOD_EEPROM_INDEX);
  setAll();
}

and will the wifi be more stable?

You gonna laugh)
The problem was in contacts.
Wires were soldered to the contacts of ENC28J60 and connected to the Arduino by dupont ends.

I gonna make a PCB and buy a mega screw shield.

And I changed the periods of timers.

set_all_timer.setInterval(3767L, setAll);
temp_timer.setInterval(19846L, tempCheckerAndSender);
protection_timer.setInterval(8478L, protectionRoutine);
online_signal_timer.setInterval(5000L, onlineSignalSender);

I don’t know why, when I tried to make multipile timer (using only one timer!) the hardware went offline in a minute.