BLYNK
BLYNK.IO       📲 GETTING STARTED       📗 DOCS       👉 SKETCH BUILDER

The hardware stops working

Okay, from the article I understood, that you disconnect the hardware witch spams the cloud.

So, I thought, that if somebody dissconects it, than somebody can connect it back.

I guessed, that you can do it because you’re an admin

I am not a Blynk Developer, just a volunteer.

Blynk doesn’t disconnect your hardware due to email or notification spamming… they (email & notifications) just stop working. I suspect they are automatically released in time.

No one is sitting around pushing the disconnect button at Blynk HQ :stuck_out_tongue: The hardware disconnections happen because your code is poorly implemented and the device cannot communicate with the server properly. There is a regular "heartbeat’ that if missed will disconnect the server link until you either reboot or run some connection management routines.

But first you have to follow the guidelines and write your code properly in order to get it to work correctly and stay connected.

1 Like

So, can I use delay() in function handled by BlynkTimer?

Because it is a totally blocking command, you shouldn’t use delay() anywhere… except perhaps in the smallest of timings ( <1 second) once in a rare moment and only where absolutely needed (falls into the “don’t do this at home unless you are an expert” category :stuck_out_tongue: ). Run BlynkTimer instances instead.

The problem is still there.

I wrote new code using recommendations.

#include <BlynkSimpleUIPEthernet.h>
const char AUTH[] = "ba2024ad11874d1d8e73cfbcf9b1fde0"; // токен для ethernet
BlynkTimer timer;

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

#define temp1_VP V1
#define temp2_VP V2

void tempCheck() {
  sensors.requestTemperatures();
  float temp1 = sensors.getTempCByIndex(0);
  float temp2 = sensors.getTempCByIndex(1);
  if (Blynk.connected()) {
    Blynk.virtualWrite(temp1_VP, temp1);
    Blynk.virtualWrite(temp2_VP, temp2);
  }
}


void setup() {
  // put your setup code here, to run once:
  sensors.begin();
  Blynk.begin(AUTH);
  Blynk.notify("Я включился! Видимо, не было электричества.");
  Blynk.syncAll();
  tempCheck();
  timer.setInterval(1000L, tempCheck);
}

void loop() {
  Blynk.run();
  timer.run();
}

What hardware are you using? Ethernet shields can be notoriously unstable.

Neither of these seems necessary with your current code. You don’t have anything that needs syncing and the timer starts running in one second anyhow for the temp reading

And neither is this… since if it is not connected then nothing happens with the following commands anyhow.

The reading of the temperature - the way it is currently implemented - causes a delay of 750ms+.

See here for a fix:

Thanks a lot! I guess it should be very helpful.

So, as I understood, that strings fix the problem?

  DS18B20.setWaitForConversion(false); // make reading NON blocking
  DS18B20.requestTemperatures();       // start conversion for first reading

These two lines are only part of the story related to the temp sensors - read again :wink:

Okay, there is my final code. It stops working!!!
Everything is good, the hardware continue working without Blynk, but it won’t connect to Blynk if you will not reboot the hardware.
Code:

#include <BlynkSimpleUIPEthernet.h>
 
const char AUTH[] = "ba2024ad11874d1d8e73cfbcf9b1fde0"; // токен для ethernet
 
BlynkTimer temp_timer;
BlynkTimer online_signal_timer;
BlynkTimer protection_signal_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 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
 
WidgetLED heater_led(heater_led_VP);
WidgetLED online_led(online_led_VP);
 
const byte PERIOD = 10;  //  heating period in minutes
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 mode;
byte heater_system_delta;
bool heater_state;
 
BLYNK_WRITE(delta_VP)
{
  byte delta = param.asInt();
  heater_system_delta = delta;
}
 
BLYNK_WRITE(mode_VP)
{
  byte new_mode = param.asInt();
  mode = new_mode;
  end_time = 0;  // for re-count in function
  heater_state = false;
}
 
void setup() {
  // put your setup code here, to run once:
  pinMode(protection_pin_1, OUTPUT);
  pinMode(protection_pin_2, OUTPUT);
  pinMode(heater, 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 
  
  Blynk.begin(AUTH);
  Blynk.notify("Я включился! Видимо, не было электричества.");
  Blynk.syncAll();
  temp_timer.setInterval(1500L, tempRoutine);
  protection_signal_timer.setInterval(750L, protectionSignalSender);
  online_signal_timer.setInterval(5000L, onlineSignalSender);
}
 
void loop() {
  Blynk.run();
  temp_timer.run();
  protection_signal_timer.run();
  online_signal_timer.run();
}
 
void tempRoutine() {
  tempCheckerAndSender();
  heaterController();
}
 
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 protectionSignalSender() {
  byte pin;
  static bool parity;
  // 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() {
  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;
        }
      }
    }
  }
  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;
  }
}```
Some ideas?
@gunner, can you help me too?

Some of your code is very odd. Take this as an example…

You’re defining a local Boolean variable called parity. It will have a value of false/zero, as you’ve just defined it and not assigned a value to it.
You’re then multiplying zero by 255 (still zero) and writing this to an LED widget.
You then do a ‘not’ on the variable, to make it have a value of 1.
However, as its a local variable and this is the end of the function, this value is then lost, as you re-define it again the next time the function is called.
Even if you’d defined this as a global variable, it would still be strange, a you’re using the same variable name in the protectionSignalSender() function, which has even more issues with the way that it’s written.

You’re doing a similar thing in your heaterController() function with the time_on and time_off variables.

You have no Serial.print statements to give you clues about what’s happening to any of these variables, so I don’t see how you can say that…

If it were me, I’d throw-in some Serial.print statements to show the key values (specially the temperature readings), reduce the frequency of the timers and comment-out all but one of your consecutive Blynk.virtualWrite statements to enable you to see what’s happening.

In addition, I’d try a very simple sketch to ensure that your Ethernet shield is working correctly, they can be very temperamental.

Pete.

1 Like

The function onlineSignalSender is used for change the state of LED each 5 seconds.
I use the construction led.setValue(x * 255), because it is faster and smaller than this once:

if (x) {
led.on();
}
else {
led.off();
}

ProtectionSignalSender sends a random signal to protector (attiny). If the signal state will not be changed for 5 minutes on each pin, attiny will reboot arduino. It is like the external watchdog

Now, I have the access to my device. After it went offline yesterday, I came to it. The hardware works normally, excepting the ENC28J60.
I guess, it was hung on, because the recieve and transmit LEDs on ENC28J60 blinked rarely and same, though it was looped.

I realise what it’s meant to do, but as I said, I don’t see how it can work when you re-declare the variable parity every time the function is called.

Pete.

I use the static qualifier, and it defines only once. More about static there

2 Likes

I learned something new today (always a good day when that happens!).
Thanks.

Pete.

2 Likes

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.