ESP8266 hangs on Blynk.virtualWrite

Hi guys,

I’m having a lot headaches trying to solve an issue is happening with my project.

I have an Aquarium Led Lamp Controlled by an ESP8266 NodeMCU Lolin.

In order to achieve a gradual and soft change of the light power during the day, I have stored on the same memory of the ESP8266 a set of photoperiod curves that I can select. They are stored as binary data.

Normally everything works fine, but sometimes (it’s a consistent error), the ESP resets or simply it hangs and stop working (right now is hanged).

I added some serial.print instructions in order to determine where exactly happens the issue, and it’s looks clear that sometimes and for an unknow reason, the Blynk.virtualWrite is causing the problem.

Let me describe my sketch. It’s big, then I’ll put what I believe are the main parts.

Initial declares and libraries:

#define BLYNK_PRINT Serial 
#include <ESP8266WiFi.h>
#include <DNSServer.h>
#include <BlynkSimpleEsp8266.h>
//#include <SoftwareSerial.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <TimeLib.h>
#include <WidgetRTC.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h>         //https://github.com/tzapu/WiFiManager
#include <ESP8266mDNS.h>
#include <ESP8266HTTPUpdateServer.h>
//#define ONE_WIRE_BUS 14  // DS18B20 pin D5(ESP8266) Compatible con tarjetas nuevas
#define ONE_WIRE_BUS 2 // DS18B20 pin D4(ESP8266) compatible tarjeta antigua
#define GraphTemp 8
#define VIRTUAL_PIN_Terminal 9
#define VIRTUAL_PIN_Menu_Modo 26
#define VIRTUAL_PIN_Luz_Luna 27
#define Update_Firmware 15 // Push Button virtual en Blynk para solicitar upgrade de Firmware OTA vía Http

extern "C"{
  #include "pwm.h"
}

////// PWM

// Period of PWM frequency -> default of SDK: 5000 -> * 200ns ^= 1 kHz

#define PWM_PERIOD 5000

// PWM channels

#define PWM_CHANNELS 4

// PWM setup (choice all pins that you use PWM)

uint32 io_info[PWM_CHANNELS][3] = {
  // MUX, FUNC, PIN
  {PERIPHS_IO_MUX_GPIO5_U, FUNC_GPIO5,   5}, // D1
  {PERIPHS_IO_MUX_GPIO4_U, FUNC_GPIO4,   4}, // D2
  {PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0,   0}, // D3
  {PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2,   2}, // D4
//  {PERIPHS_IO_MUX_MTMS_U,  FUNC_GPIO14, 14}, // D5
//  {PERIPHS_IO_MUX_MTDI_U,  FUNC_GPIO12, 12}, // D6
//  {PERIPHS_IO_MUX_MTCK_U,  FUNC_GPIO13, 13}, // D7
//  {PERIPHS_IO_MUX_MTDO_U,  FUNC_GPIO15 ,15}, // D8
                         // D0 - not have PWM :-(
};

// PWM initial duty: all off

uint32 pwm_duty_init[PWM_CHANNELS];

// Dimmer variables

//int16_t duty = 0;
//int16_t step = 1;

const size_t len_curvas = 6126;
const uint8_t curvas[] PROGMEM = {0x00,0x00,0x00,0x01,0x00,0x01,..... a lot of binary data.... }

BlynkTimer timer;
WidgetRTC rtc;
WidgetTerminal terminal(VIRTUAL_PIN_Terminal); // Attach virtual serial terminal to Virtual Pin

//OneWire oneWire(ONE_WIRE_BUS);
//DallasTemperature DS18B20(&oneWire);



float oldTemp = -1;
float temp;
int PWM_Digital_Canal[4] = { 4, 0, 5, 14};
int VIRTUAL_PIN_Fotoperiodo_Canal[4] = { 18, 19, 20, 21};
int Graph_Canal[4] = { 10, 11, 12, 13};
int PWM_Virtual_Canal[4] = { 0, 1, 2, 3};
int Luz[4];
int luz_anterior[4];
int deltaLuz[4];
int potCanal[4] = {0, 0, 0, 0};
int posmem;
int Modo = 1;
int Luz_Luna = 1;
String Modo_txt[5] = {"Manual", "Despejado", "Nubes Suaves", "Nubes Intensas"};
char auth[] = "a20e960c059046f4bff8daf51381fbe0";   // Auth Token Blynk Luis Rossel
int FotoPeriodo_Inicio_Canal[4] = { 300, 300, 300, 300};
int FotoPeriodo_Fin_Canal[4] = { 1320, 1320, 1320, 1320};
int Minuto_Ajustado;
const char* host = "esp8266-webupdate";
int updateWeb = 0;

ESP8266WebServer httpServer(80);
ESP8266HTTPUpdateServer httpUpdater;

I have a function called every 60 seconds to update the light power according to the time of the day and some time inputs setups:

void actualizaLuzTemp()
{
  int t = now(); // Guarda la hora actual en t
  String currentTime = String(hour()) + ":" + minute();
  int h = hour(t);  // returns the hour for the given time t
  int m = minute(t);// returns the minute for the given time t
  int i;
  switch (Modo)
  {
    case 1:
    for (i = 0; i < 4; i = i + 1) 
    {
      potCanal[i] = Luz[i];
      pwm_set_duty(potCanal[i], i );
      pwm_start(); // commit
    }
    break;
    default:
    for (i = 0; i < 4; i = i + 1) 
    {
      if ( (FotoPeriodo_Fin_Canal[i] - FotoPeriodo_Inicio_Canal[i]) != 0 )
      {
        Minuto_Ajustado = ( h*60 + m - FotoPeriodo_Inicio_Canal[i]) * 1020 / (FotoPeriodo_Fin_Canal[i] - FotoPeriodo_Inicio_Canal[i]);  
      }
      else
      {
        Minuto_Ajustado = ( h*60 + m - FotoPeriodo_Inicio_Canal[i]);
        Serial.println("Error de fotoperiodo");
      }
      if ( Minuto_Ajustado < 0 ) Minuto_Ajustado = 0;
      if ( Minuto_Ajustado > 1020) Minuto_Ajustado = 1020;
      posmem = (Modo-2)*2042 + (Minuto_Ajustado)*2;
      uint8_t byteval_1 = pgm_read_byte(curvas + posmem);
      posmem = posmem + 1;
      uint8_t byteval_2 = pgm_read_byte(curvas + posmem);
      if ( Luz[i] > 100) Luz[i] = 100;
      potCanal[i] = (byteval_1*256 + byteval_2)*Luz[i]/100;
      
      if ( (i == Luz_Luna - 2) && (potCanal[i] <= 10) ) potCanal[i] = 50;
      int x;
      x = luz_anterior[i] - potCanal[i];
      if ( abs(x) >= 500 )
      {
        deltaLuz[i] = ( potCanal[i] - luz_anterior[i] ) / 10;
        int Conteo_Segundos = 0;
        int millis_anterior = 0;
        int millis_actual = 0;
//      terminal.println(F("-----------------"));
        Serial.println("* Cambio  Suave *");
        terminal.println(F("* Cambio  Suave *"));
        terminal.flush();
        Blynk.disconnect();
        while (Conteo_Segundos < 10)
        {
          millis_actual = millis();
          yield();
          if ( (millis_actual - millis_anterior) > 1000 )
          {
            millis_anterior = millis_actual;
            Conteo_Segundos = Conteo_Segundos + 1;
            potCanal[i] = luz_anterior[i] + deltaLuz[i];
            if ( ( i == Luz_Luna - 2 ) && ( potCanal[i] <= 50 ) && ( potCanal[i] <= luz_anterior[i] ) ) potCanal[i] = 50;
            pwm_set_duty(potCanal[i], i );
            pwm_start(); // commit
            luz_anterior[i] = potCanal[i];
            }
         }
         Blynk.connect();
       }
      pwm_set_duty(potCanal[i], i );
      pwm_start(); // commit 
      luz_anterior[i] = potCanal[i];  
    }
    break;
  }
//  leeTemperatura();
//  Blynk.virtualWrite(GraphTemp, temp);
//  terminal.print(String( temp)+"°C - ");
  Serial.println(currentTime);
  Serial.println(Modo_txt[Modo-1]);

  for (i = 0; i < 4; i = i+1 )
  {
    Serial.print("Canal ");
    Serial.print(String(i+1));
    Serial.print(": ");
    Serial.print(String(potCanal[i]));
    if ( ( i == Luz_Luna - 2 ) && ( potCanal[i] <= 50 ) ) Serial.print(" Luna");
    Serial.println("");
  }
  Serial.println(F("-----------------"));
    if (Blynk.connected()==true) {
      Serial.print("*Blynk");
      Blynk.virtualWrite(V10, potCanal[0]);
      delay(50);   
      Blynk.virtualWrite(V11, potCanal[1]);
      delay(50);
      Blynk.virtualWrite(V12, potCanal[2]);
      delay(50);
      Blynk.virtualWrite(V13, potCanal[3]);
      delay(50);
      Serial.println("Blynk*");
  }

I determined that the problem happens at the last part:

if (Blynk.connected()==true) {
  Serial.print("*Blynk");
  Blynk.virtualWrite(V10, potCanal[0]);
  delay(50);   
  Blynk.virtualWrite(V11, potCanal[1]);
  delay(50);
  Blynk.virtualWrite(V12, potCanal[2]);
  delay(50);
  Blynk.virtualWrite(V13, potCanal[3]);
  delay(50);
  Serial.println("Blynk*");
  }

This is the serial console ouput:

11:19
Nubes Suaves
Canal 1: 0
Canal 2: 4364
Canal 3: 4990
Canal 4: 0
-----------------
*BlynkBlynk*
[2050152] Time sync: OK
11:20
Nubes Suaves
Canal 1: 0
Canal 2: 4386
Canal 3: 4989
Canal 4: 0
-----------------
*BlynkBlynk*
11:21
Nubes Suaves
Canal 1: 0
Canal 2: 4408
Canal 3: 4987
Canal 4: 0
-----------------
*BlynkBlynk*
11:22
Nubes Suaves
Canal 1: 0
Canal 2: 4419
Canal 3: 4983
Canal 4: 0
-----------------
*Blynk

As you can see, the first serial print was executed, but after that, the ESP just stopped working, not reset, not turn off, just stopped.

At this moment, the leds are ON, and luckily, my corals and fishes are with good light from the lamp.

Any Ideas?

just ideas:

  • just to be sure, comment out the “last part” if statement, and see if the problem disappears

  • for more detailed debug, put a serial.println(millis()) after EACH line in the “last part” to see how long it takes to execute

  • update the arduino ide to latest, esp core to 2.4 and re-upload the code

  • maybe put a serial.println(millis()) into the main loop, with high baud rate (250000) to see if the code takes too long to execute at some point (for example, eeprom writes can take a lot of time)

  • enable blynk serial debug to see what is going on with blynk

  • check psu quality, wireing, peripherals

Normally caused by bad array code, ESP will usually recover but it can be 5 minutes or more and never if you haven’t rebooted once since your last flash.

Thanks for the ideas @wanek

  • I added the If statement suspecting that a lost of connection could be guilty of the fail. But the problem still happens adding this condition. Then, this is not the cause.
  • I’ll do that as a second try.
  • I updated Arduino IDE to 1.8.5, mine was 1.8.3
  • I’ll do that as a third try.

Thanks again!

Following your suggestion I increased the size of the array on declare:

float oldTemp = -1;
float temp;
int PWM_Digital_Canal[5] = { 4, 0, 5, 14};
int VIRTUAL_PIN_Fotoperiodo_Canal[5] = { 18, 19, 20, 21};
int Graph_Canal[5] = { 10, 11, 12, 13};
int PWM_Virtual_Canal[5] = { 0, 1, 2, 3};
int Luz[5];
int luz_anterior[5];
int deltaLuz[5];
int potCanal[5] = {0, 0, 0, 0};
int posmem;
int Modo = 1;
int Luz_Luna = 1;
String Modo_txt[5] = {"Manual", "Despejado", "Nubes Suaves", "Nubes Intensas"};
char auth[] = "a20e960c059046f4bff8daf51381fbe0";   // Auth Token Blynk Luis Rossel
int FotoPeriodo_Inicio_Canal[5] = { 300, 300, 300, 300};
int FotoPeriodo_Fin_Canal[5] = { 1320, 1320, 1320, 1320};
int Minuto_Ajustado;
const char* host = "esp8266-webupdate";
int updateWeb = 0;

I’m testing now.

Thanks again @Costas

what do you mean by this exactly?

It just happened again. ESP8266 hangs, and the last prints on serial console, included the blynk debug are:

15:42
Nubes Suaves
Canal 1: 1361
Canal 2: 4064
Canal 3: 3573
Canal 4: 0
-----------------
*Blynk
[1713074] <[14|01|0E|00|0A]vw[00]10[00]1361
*Blynk1
[1713371] <[14|01|0F|00|0A]vw[00]11[00]4064
*Blynk2
[1713679] <[14|01|10|00|0A]vw[00]12[00]3573
*Blynk3
[1714001] <[14|01|11|00|07]vw[00]13[00]0
Blynk*
[1721275] <[06|01|12|00|00]
[1721520] >[00|01|12|00|C8]
[1731515] <[06|01|13|00|00]
[1731754] >[00|01|13|00|C8]
[1741755] <[06|01|14|00|00]
[1741995] >[00|01|14|00|C8]
[1751996] <[06|01|15|00|00]
[1752234] >[00|01|15|00|C8]
[1762235] <[06|01|16|00|00]
[1762473] >[00|01|16|00|C8]
[1772474] <[06|01|17|00|00]
[1772714] >[00|01|17|00|C8]
15:43
Nubes Suaves
Canal 1: 1373
Canal 2: 4076
Canal 3: 3584
Canal 4: 0
-----------------
*Blynk
[1773074] <[14|01|18|00|0A]vw[00]10[00]1373
*Blynk1
[1773379] <[14|01|19|00|0A]vw[00]11[00]4076
*Blynk2
[1773688] <[14|01|1A|00|0A]vw[00]12[00]3584
*Blynk3
[1773992] <[14|01|1B|00|07]vw[00]13[00]0
Blynk*
[1782715] <[06|01|1C|00|00]
[1783045] >[00|01|1C|00|C8]
[1792980] <[06|01|1D|00|00]
[1793143] >[00|01|1D|00|C8]
[1803143] <[06|01|1E|00|00]
[1803332] >[00|01|1E|00|C8]
[1813333] <[06|01|1F|00|00]
[1813574] >[00|01|1F|00|C8]
[1823575] <[06|01] [00|00]
[1823810] >[00|01] [00|C8]
15:44
Nubes Suaves
Canal 1: 1387
Canal 2: 4100
Canal 3: 3595
Canal 4: 0
-----------------
*Blynk
[1833074] <[14|01]![00|0A]vw[00]10[00]1387
*Blynk1
[1833385] <[14|01]"[00|0A]vw[00]11[00]4100
*Blynk2
[1833692] <[14|01]#[00|0A]vw[00]12[00]3595

I can notice something strange at the Blynk messages befor the “15:44” print, like a missing data.

This is weird too!

*Blynk
[1833074] <[14|01]![00|0A]vw[00]10[00]1387
*Blynk1
[1833385] <[14|01]"[00|0A]vw[00]11[00]4100
*Blynk2
[1833692] <[14|01]#[00|0A]vw[00]12[00]3595

Look at the symbols after [14|01]

Badly written code for arrays is notorious for writing to out of bound memory areas which will shutdown the ESP until it thinks it’s safe to resurface. As it does an internal reset it will only reboot if it has had a manual reboot since it was last flashed.

e.g. stuck at

 ets Jan  8 2013,rst cause:4, boot mode:(1,7)

wdt reset

That is standard practise.

I’m sorry to bother you. Where do you suspect I have bad code?

I’m not sure I can see where it hangs. Comment out the virtualWrite() of the array elements and show Serial Monitor values for the elements.

I just copied the serial console output. May be I’m wromg, but I suppose the last line printed was the las action the ESP did.

I’ll comment the Blynk.virtualWrite and let it run again. I can bet that it will not hang… hopefully :frowning:

@Costas, maybe i’m wrong, but couldn’t be possible the same issue i had with old esp core? his code is quite big and complex, maybe the esp is a bit overloaded…

@lrossel, what core version do you have?

@wanek, I’m pretty sure I’ll sound very ignorant… where I can see that?

if you have “show verbose output during compilation upload” enabled at one point will be visible there, or you can check in arduino ide preferences > additional board manager url, but probably there are nicer ways for finding the core version, @costas?

They are the 2 places I look @wanek

In arduino ide preferences > additional board manager url I have:
http://arduino.esp8266.com/stable/package_esp8266com_index.json

I have it running now with the Blynk.virtuaWrite commented:

if (Blynk.connected()==true) {
  Serial.println("*Blynk");
//      Blynk.virtualWrite(V10, potCanal[0]);
  delay(50);
  Serial.println("*Blynk1");   
//      Blynk.virtualWrite(V11, potCanal[1]);
  delay(50);
  Serial.println("*Blynk2");
//      Blynk.virtualWrite(V12, potCanal[2]);
  delay(50);
  Serial.println("*Blynk3");
//      Blynk.virtualWrite(V13, potCanal[3]);
  delay(50);
  Serial.println("Blynk*");
  }

Let me guess… no, I can’t. :rofl:

Any clues?

@lrossel but replace each virtualWrite() with Serial.print() so the first becomes:

//Blynk.virtualWrite(V10, potCanal[0]); 
Serial.println(potCanal[0]);