No me salen notificaciones en el móvil

Nunca he trabajado con funciones lamdba ni con lo segundo que comentas… Veré qué encuentro y cómo puedo reestructurar mi código…

Lambda are probably easier.

This is the equivalent of a 5 second delay, followed by activating a relay…

  timer.setTimeout(5000L, []() 
  {  // Wait 5 seconds then...
     digitalWrite(relay3, HIGH);  // Turn relay3 On
    // put any other actions in here...
  });  // END Lambda Function

Edited to add…

You need to have declared the BlynkTimer object called timer first…

BlynkTimer timer;

and have timer.run(); in your void loop.

Pete.

Vale muchas gracias, probaré este fin de semana. Sí, tengo el timer ya creado e iniciado, de hecho lo llamo dentro del bucle while del código que mostré anteriormente.

Muchas gracias!

Estoy teniendo problemas con el bucle for. Me cambia el valor de la variable i correctamente, pero no ejecuta lo que hay dentro del bucle hasta que i alcanza su valor máximo, es decir, en el último ciclo. ¿Hay algún problema al usar este tipo de bucles en blynk?

for (int i = 1; i <= numSesiones; i++) {
          sesionActual = i;
          timer.setInterval(1000L, sendSensor);
          unsigned long totalCiclo = tiempoCiclo * 60 * 1000;
          timer.setTimeout(totalCiclo, []()
          { // Esperar lo que dura un ciclo y...
            Blynk.notify(String("Ciclo finalizado. Descanse ") + tiempoDescanso + String(" minutos."));
            unsigned long totalDescanso = tiempoDescanso * 60 * 1000;
            timer.setTimeout(totalDescanso, []()
            { // Esperar lo que dura el descanso y...
              Blynk.notify("Comienza el siguiente ciclo.");
            }); // END Lambda Function
          }); // END Lambda Function
        }
        Blynk.notify("Entrenamiento finalizado.");

There isn’t a problem with using for loops within Blynk, provided yo use them correctly.

You have to remember that the void loop won’t execute until the for loop has completed, which in your case means that timer.run won’t be called - so none of your timers will increment.
Also, Blynk.run won’t execute either, so if this loop takes more than 10 seconds to execute then your device will disconnect from the Blynk server.

You also need to be very careful; about using nested lambda functions, this probably isnt the best way to achieve what you want.

Also, I can’t understand why you’d initialise multiple setInterval timers as part of a loop like this. You should almost certainly be initialising that time in your void setup.

Pete.

Este bucle for se encuentra dentro de la función de un botón, es decir, cuando se pulsa, ejecuta eso y otras acciones más. De hecho, antes del bucle tengo otras funciones lambda con setTimeout también y funcionan perfectamente. Lo único que me está dando problemas es el bucle, que funciona raro, solo ejecuta el código en la última repetición y encima después de enviar la notificación que queda fuera del bucle.

En relación a Blynk, en el loop() tengo Blynk.run(); y timer.run(); y en el setup() tengo

Blynk.begin(auth, ssid, pass, IPAddress(x, x, x, x), 8080); 
Blynk.virtualWrite(V37, "Establezca los parámetros de su entrenamiento");

I’ve explained why you are getting this weird behaviour - because your void loop isn’t being executed, so your timer object isn’t being services, and Blynk isn’t being serviced either.

You need to restructure your code and probably use a timer to evaluate the numSesiones test rather than a for loop.

Pete.

He conseguido hacerlo y la variable sesionActual se me actualiza correctamente cuando acaba un ciclo, pero luego no me vuelve a aplicar los tiempo de ciclo, y en la función de sendSensor no puedo ponerlos. ¿Cómo podría hacer?

void sendSensor()
{
  if (sesionActual <= numSesiones) {
    Blynk.virtualWrite(V35, (tiempoCiclo + tiempoDescanso) * numSesiones);
    Blynk.virtualWrite(V1, SPO2);
    Blynk.virtualWrite(V2, BPM);
    Blynk.virtualWrite(V3, VRE);
    Blynk.virtualWrite(V4, VRI);
    Blynk.virtualWrite(V5, FR);
    Blynk.virtualWrite(V36, sesionActual);
  } else {
    Blynk.notify("Entrenamiento finalizado.");
    inicioVariables();
  }
}

BLYNK_WRITE(V34) {
  startTraining = param.asInt();
  if (startTraining == 1) { // si se pulsa
    Blynk.notify("Espere hasta que la máquina se prepare para acceder al control fisiológico.");
    // Funcion lambda: equivalente a delay
    timer.setTimeout(10000L, []()
    { // Esperar 10s y luego...
      Blynk.virtualWrite(V39, "Máquina lista. ¡Ha comenzado tu entrenamiento!");
      sesionActual = 1;
      timer.setTimeout(5000L, []()
      { //Esperar 5s y luego...
        Blynk.virtualWrite(V39, "Ve a Sensórica para seguir tu entrenamiento.");
      });  // END Lambda Function
    });  // END Lambda Function
    timer.setInterval(1000L, sendSensor);
    unsigned long totalCiclo = tiempoCiclo * 60 * 1000;
    timer.setTimeout(totalCiclo, []()
    { // Esperar lo que dura un ciclo y...
      Blynk.notify(String("Ciclo finalizado. Descanse ") + tiempoDescanso + String(" minutos."));
      unsigned long totalDescanso = tiempoDescanso * 60 * 1000;
      timer.setTimeout(totalDescanso, []()
      { // Esperar lo que dura el descanso y...
        Blynk.notify("Comienza el siguiente ciclo.");
        sesionActual = sesionActual + 1;
      }); // END Lambda Function
    }); // END Lambda Function
  }
}

I don’t have a high level overview of what it is that you’re trying to achieve, so it’s difficult to provide any advice.
However, I still don’t understand why you’re using notifications rather than a value widget or a terminal widget to give step-by-step instructions.

Pete.

Estaba usando notificaciones porque me resultaba la manera más directa de que el usuario se enterara del fin de un evento. Dada la problemática que presentan, he probado a hacerlo como me decías, con value widgets, y la verdad que ya no tengo el problema anterior. Aún así, tengo que depurar 2 funciones lambda seguidas… Pues los mensajes que muestro en el value widgets se van sobreescribiendo continuamente una vez entra en la 2º función lambda.

void sendSensor()
{
  if (sesionActual <= numSesiones) {
    Blynk.virtualWrite(V35, (tiempoCiclo + tiempoDescanso) * numSesiones);
    Blynk.virtualWrite(V1, SPO2);
    Blynk.virtualWrite(V2, BPM);
    Blynk.virtualWrite(V3, VRE);
    Blynk.virtualWrite(V4, VRI);
    Blynk.virtualWrite(V5, FR);
    Blynk.virtualWrite(V36, sesionActual);
    unsigned long totalCiclo = tiempoCiclo * 60 * 1000;
    timer.setTimeout(totalCiclo, []()
    { // Esperar lo que dura un ciclo y...
      Blynk.virtualWrite(V40, String("Ciclo finalizado. Descanse ") + tiempoDescanso + String(" min."));
      unsigned long totalDescanso = tiempoDescanso * 60 * 1000;
      timer.setTimeout(totalDescanso, []()
      { // Esperar lo que dura el descanso y...
        Blynk.virtualWrite(V40, "Comienza el siguiente ciclo. Entrenando...");
        sesionActual = sesionActual + 1;
      }); // END Lambda Function
    }); // END Lambda Function
  } else {
    Blynk.virtualWrite(V40, "Entrenamiento finalizado.");
  }
}

Vale, además del problema mencionado en el post anterior, solo entra la primera vez a la función lambda 1; una vez recorre las 2, solo espera el tiempo indicado por la segunda… No sé donde poner exactamente estas funciones, pero donde mejor resultado tiene es donde está ahora, aunque hay que resolver esos 2 fallos.

Pete.

En la interfaz establecemos los tiempos que dura un ciclo, un descanso, y el número de repeticiones. En base a eso, creamos un entrenamiento, que comienza pulsando el botón Start. En la función de Blynk_Write(V34) se aprecia cómo se inicia un entrenamiento y se ve el momento en el que se empiezan a enviar los datos.

Estos datos se mandan siempre, pero el entrenamiento debe acabar, y cuando eso pase los datos se dejarán de mandar. Además, hay que establecer ‘cronómetros’ para controlar los tiempos de ciclo y de descanso, pues al usuario le damos indicaciones por la interfaz a través de LEDs para que sepa cuando descansar y cuando seguir, así como avisar de que el entrenamiento acabó del todo. Todo esto se ha programado en la función sendSensor().

Espero que con esta aclaración y poniendo el código debajo, lo entienda mejor. Gracias.

void sendSensor()
{
  // Siempre que la sesión actual no supere el máximo de sesiones establecidas, tomamos lectura de datos
  if (sesionActual <= numSesiones) {
    Blynk.virtualWrite(V1, SPO2);
    Blynk.virtualWrite(V2, BPM);
    Blynk.virtualWrite(V3, VRE);
    Blynk.virtualWrite(V4, VRI);
    Blynk.virtualWrite(V5, FR);
    Blynk.virtualWrite(V35, (tiempoCiclo + tiempoDescanso) * numSesiones);
    Blynk.virtualWrite(V40, "Entrenando...");
    Blynk.virtualWrite(V36, sesionActual);
    led3.off();
    unsigned long totalCiclo = tiempoCiclo * 60 * 1000;
    // Funcion lambda: equivalente a delay
    timer.setTimeout(totalCiclo, []()
    { // Esperar lo que dura un ciclo y...
      led1.on();
      unsigned long totalDescanso = (tiempoDescanso * 60 * 1000);
      timer.setTimeout(totalDescanso, []()
      { // Esperar lo que dura el descanso y...
        led1.off();
        led2.on();
        delay(3000);
        led2.off();
        Blynk.virtualWrite(V40, "Comienza el siguiente ciclo.");
        sesionActual = sesionActual + 1;
      }); // END Lambda Function
    }); // END Lambda Function
  } else { // En cuanto se superan las sesiones, finalizamos entrenamiento
    Blynk.virtualWrite(V40, "Entrenamiento finalizado.");
    led3.on();
    inicioVariables();
  }
}

// Iniciar entrenamiento al pulsar el botón Start
BLYNK_WRITE(V34) {
  startTraining = param.asInt();
  if (startTraining == 1) { // si se pulsa
    Blynk.notify("Espere hasta que la máquina se prepare para acceder al control fisiológico.");
    // Funcion lambda: equivalente a delay
    timer.setTimeout(10000L, []()
    { // Esperar 10s y luego...
      Blynk.virtualWrite(V39, "Máquina lista. ¡Ha comenzado tu entrenamiento!");
      sesionActual = 1;
      timer.setTimeout(5000L, []()
      { //Esperar 5s y luego...
        Blynk.virtualWrite(V39, "Ve a Sensórica para seguir tu entrenamiento.");
        Blynk.virtualWrite(V40, "Entrenando...");
        timer.setInterval(1000L, sendSensor);
      });  // END Lambda Function
    });  // END Lambda Function
  } else { // si está 'off' todas las variables se ponen a 0
    inicioVariables();
  }
}

Okay, that level of detail would have been useful much earlier on in the conversation.

Personally, I’d take a much different approach…

I’d have function that is called using an timer once every second.
If there is a training session on progress (I’d use a flag to know this) then I’d decrease the remaining time by one second, and update a display in the app which shows remaining time for that session.

I’d do a similar thing for the rest sessions.

Once the last training session is ended, no rest session is needed, but the results of the sessions can then be written to the app.

No need for timeout timers at all in this scenario.

Pete.

Mmmm interesante. La cosa es que estuve mirando los displays de tiempo y no sabía exactamente cómo hacer para que me funcionara como quería. La verdad que consiguiendo eso simplificaría bastante todo, pero no se plantearlo bien. ¿Alguna referencia en la que basarme para hacer lo que me dices?

Un último apunte, en la última sesión de entrenamiento también usaría el tiempo de descanso, pues quiero seguir monitorizándolo para comparar y sacar datos de las sesiones al completo.

A description in “[pseudo code” of how I’d approach it…

Timer runs every second and calls the training_timer function

Global variable to hold remaining_training_time, which initially comes from either a widget, or a parameterised variable

training_timer fiunction would…

Check if remaining_training_time >0 (if it is, then a training session is running)
Subtract 1 (second) from remaining_training_time
Send remaining_training_time to a value widget, after converting into minutes:seconds format

Check if remaining_training_time is now ==0 (if it is then training sessionn has just ended and you need to start the rest session. Set the remaining_rest_time to whatever value it should be. The rest session countdown is handled in the same way as above

Pete.

Funciona perfectamente! Sólo hay una pega, y es que cuando el remaining_rest_time == 0, habrá acabado una sesión, y las variables de remaining_training_time y remaining_rest_time deberán retornar a su valor original, no quedarse en 0. He intentado varios métodos pero no soy capaz de restaurar el valor que cogía del slider.

The Blynk.syncVirtual(vPin) command will force the BLYNK_WRITE(vPin) callback function to trigger.
If your code on the BLYNK_WRITE(vPin) simply sets a global variable to the slider value using param.asInt() command then it will re-populate your global variable with the current slider value.

Alternatively, you could use two separate variables. One to hold the slider value, and another to do the countdown (which is really what I was suggesting above).

Pete.

No había caído en Blynk.syncVirtual(vPin). Funciona perfecto, muchas gracias Pete, podemos dar por cerrado el caso.

1 Like