Adding a sub-menu and assign it different instructions

Details :
• Hardware model: esp8266 D1 mini
• Smartphone OS (Android) + 5.xx
• Blynk server
Hi,
I was wondering if I can add a sub-menu with totally different functions from the main one. Is this possible from the hardware?
I’ve made a sketch already, and I’ve succeeded to make it back to the main menu.
However, the setProperty option just change the labels. for my case, I need something a little bit different.
I can provide you with a video to make things clear.
Any ideas?
ezgif.com-video-to-gif

Watching your video, and reading what you’ve written still leaves me unsure what it is that you’re trying to achieve.
Maybe you can explain in a less hypothetical way what it is exactly you’re trying to achieve?

Pete.

Thanks for your feedback
Maybe I have to reform my question.
Can I use param.asStr instead of param,asInt to manipulate the menu widget?

Param.asInt(), param.asStr() and param.asFloat won’t manipulate the menu widget, they are methods of retrieving the data coming from the widget and assigning the result to a variable.

With the menu widget you get the index ID returned from the widget, which is an integer, so param.asInt() is the appropriate method to use.

I’m guessing, from the very limited information you’ve provided, that you want to Chang the menu text and do different things when the altered menu option is chosen.
If that’s the case then the solution is fairly simple. You are in control of the menu options that have been sent from your code, so you need to manage what happens when a certain combination of menu text and menu ID are encountered.

Pete.

Could you make a sketch as an example?
Thanks in advance

Maybe you should share what you have so far, and EXPLAIN IN DETAIL what it is that you are trying to achieve, rather than leaving us guessing?

Pete.

I’ll try to make it clear this time.
This is what I’ve reached so far:

#define BLYNK_PRINT Serial

#include <BlynkSimpleEsp8266.h>
#include <ESP8266WiFi.h>
#include <Ticker.h>


// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
char auth[] = "))))))))))))";
char ssidblynk[] = "*=* dP *=*";
char passblynk[] = "_è-('è_çà";


Ticker Triger;
void changeState()
{
  digitalWrite(trigPin, !(digitalRead(trigPin)));  //Invert Current State of LED
}

WidgetLCD lcd(V2);


BLYNK_WRITE(V1) {
  int value = param.asInt();
//Create menu list items from hardwar
  BlynkParamAllocated items(128); // list length, in bytes
    items.add("RP");//value=1
    items.add("E8");//value=2
    items.add("AE");//value=3
    Blynk.setProperty(V1, "labels", items);
  if (value == 1) {
    Serial.println("RP");
    lcd.clear(); //Use it to clear the LCD Widget
    lcd.print(0, 0, "RP");
    //Create new menu list items from hardwar
    BlynkParamAllocated items(128); // list length, in bytes
    items.add("item L");
    items.add("item U");
    items.add("item T");
    items.add("Back");//value=4 to return to the main menu
    Blynk.setProperty(V1, "labels", items);
  } else if (value == 2) {
    Serial.println("E8");
    lcd.clear(); //Use it to clear the LCD Widget
    lcd.print(0, 0, "E8"); 
    // If item 2 is selected, change menu items...
    BlynkParamAllocated items(128); // list length, in bytes
    items.add("item L s");
    items.add("item U s");
    items.add("item T s");
    items.add("Back");
    Blynk.setProperty(V1, "labels", items);
  } 
  else if(value==3){
    Serial.println("AE");    
    lcd.clear(); //Use it to clear the LCD Widget
    lcd.print(0, 0, "AE");
    // If item 2 is selected, change menu items...
    BlynkParamAllocated items(128); // list length, in bytes
    items.add("item L a");
    items.add("item U a");
    items.add("item T a");
    items.add("Back");
    Blynk.setProperty(V1, "labels", items);
  }
  else {
    BlynkParamAllocated items(128); // list length, in bytes
    items.add("RPA");
    items.add("E8");
    items.add("AE");
    Blynk.setProperty(V1, "labels", items);
  }
}

Now, All I want is:
-When I click on RP the menu list changes and new instructions will take effect.
-The new list has 4 choices now, let’s pick out the third one.
-the third one named item U it should have completely different instructions "ex: blink an led for 3 minutes "
-the fourth choice it has the capability to go back to the main menu which has three choices : RP , E8 and AE
I hope it’s clear enough now.

I’d be happy to ask me for more details.

Okay, so the way I would approach this is as follows…

You have three menus:

Menu 1 - RP, EB, AE
Menu 2 - L, U, T
Menu 3 RPA, E8, AE

I would use a global variable - lets call it currentMenu which I’d use to track which menu is in use.

You then check which menu is in use and what value has been returned for the menu index ID. something like this piece of pseudo code…

if (currentMenu == 1)
{
  if (menuIndexID ==1)
  {
    \\Do your "RP" processing here.... 
  }
  if (menuIndexID ==2)
  {
    \\Do your "EB" processing here.... 
  }
  if (menuIndexID ==3)
  {
    \\Do your "AE" processing here.... 
  }
if (currentMenu == 2)
{  
  if (menuIndexID ==1)
  {
    \\Do your "L" processing here.... 
  }
  if (menuIndexID ==2)
  {
    \\Do your "U" processing here.... 
  }
...... etc etc.

How you structure this within your code, us up to your personal preferences.
You may wish to use a switch/case statement instead of if and you may wish to have this logic contained within a separate function and either pass the menuIndexID as a parameter, or use global variables for everything.

Pete.

Thanks, Pete, and sorry for my poor response time.
Am I on the right way?


/* Comment this out to disable prints and save space */
#define BLYNK_PRINT Serial

#include <BlynkSimpleEsp8266.h>
#include <ESP8266WiFi.h>
#include <Ticker.h>


// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
char auth[] = "";
char ssidblynk[] = "*=* dP *=*";
char passblynk[] = "";

#define echoPin 8 // Echo Pin
#define trigPin 1 // Trigger Pin
long duration, distance; // Duration used to calculate distance

Ticker Triger;
void changeState()
{
  digitalWrite(trigPin, !(digitalRead(trigPin)));  //Invert Current State of LED
}
Ticker Blink;
void staticBlink() {
  digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}

WidgetLCD lcd(V2);
//Serial.clear;
/*
int currentMenu=1;
BLYNK_WRITE(V1) {
  int MenuIndexID=param.asInt();

Blynk.setProperty(V1,"labels","RPA","EC","ASE");
if (currentMenu==1)
{
  
  Blynk.setProperty(V1,"labels","L rpa","U rpa","T rpa","Back");
  Serial.println("RPA selected");
 
  if (MenuIndexID==1)
  {
    Serial.println("L RPA selected");
  }
  else if (MenuIndexID==2){
    Serial.println("U RPA selected");
  }
  else if (MenuIndexID==3){
    Serial.println("U RPA selected");
  }
  else {
    currentMenu=0;//Back to the main
    MenuIndexID=currentMenu;
  }
 
}
if (currentMenu==2)
{
  Blynk.setProperty(V1,"labels","L EC","U EC","T EC","Back");
  Serial.println("EC selected");
  int MenuIndexID=param.asInt();
  currentMenu=MenuIndexID;
  if (MenuIndexID==1)
  {
    Serial.println("L EC selected");
  }
  else if (MenuIndexID==2){
    Serial.println("U EC selected");
  }
  else if (MenuIndexID==3){
    Serial.println("U EC selected");
  }
  else {
    currentMenu=0;
    MenuIndexID=currentMenu;
  }
}
if (currentMenu==3)
{
  Blynk.setProperty(V1,"labels","L ASE","U ASE","T ASE","Back");
  Serial.println("ASE selected");
  int MenuIndexID=param.asInt();
  currentMenu=MenuIndexID;
  if (MenuIndexID==1)
  {
    Serial.println("L ASE selected");
  }
  else if (MenuIndexID==2){
    Serial.println("U ASE selected");
  }
  else if (MenuIndexID==3){
    Serial.println("U ASE selected");
  }
  else {
    currentMenu=0;
    MenuIndexID=currentMenu;
  }
}
}
  
 
void setup()
{
  // Debug console
  Serial.begin(9600);

  Blynk.begin(auth, ssidblynk, passblynk);
 
  }

void loop()
{
  Blynk.run();

}

It isn’t the way I’d have done it, and I’m finding it difficult to follow your logic.

Maybe part of that is my lack of understanding of your menu structure, and the lack of in-code documentation.

I would have expected every Blynk.setProperty(V1,"labels","...”) command to be followed by an update to the `currentMenu’ value.

and I don’t understand the logic of what you’re doing here…

But, the most important thing is that you end-up with some code that works for you and that you are able to maintain going forward. If what you have meets that criteria then it’s good to go.

Pete.

In fact, It didn’t work properly at all.
I’ve posted it to help me figure out where is the problem.
the part

works just fine. It helped me to go back to the first menu.

It might work fine, but the logic is flawed.
MenuIndexID is a pointer (which comes from the BLYNK_WRITE callback via the MenuIndexID=param.asInt() command) to indicate which index you’ve loaded into the menu widget. Setting the MenuIndexID pointer to a different menu item doesn’t change which menu item is selected, and currentMenu is a different pointer to a different entity.

Making one equal to the other isn’t an approptriate thing tpo do in this situation (in my opinion).

I this this is where you need to focus, as that’s what’s missing from your code.

Pete.

After I followed the setProperty by an update, I flooded by " RPA selected
L RPA selected
ASE selected
L ASE selected
…" like a loop. It didn’t stop until I plugged it out from the power supply.
This is my code:


#include <BlynkSimpleEsp8266.h>
#include <ESP8266WiFi.h>

char auth[] = "";
char ssidblynk[] = "*=* dP *=*";
char passblynk[] = "";



WidgetLCD lcd(V2);


int currentMenu=1;
BLYNK_WRITE(V1) {
  int MenuIndexID=param.asInt();

Blynk.setProperty(V1,"labels","RPA","EC","ASE");
Blynk.syncVirtual(V1);
if (currentMenu==1)
{
  
  Blynk.setProperty(V1,"labels","L rpa","U rpa","T rpa","Back");
  Blynk.syncVirtual(V1);
  Serial.println("RPA selected");
 
  if (MenuIndexID==1)
  {
    Serial.println("L RPA selected");
  }
  else if (MenuIndexID==2){
    Serial.println("U RPA selected");
  }
  else if (MenuIndexID==3){
    Serial.println("T RPA selected");
  }
  else {
    currentMenu=0;//Back to the main
    
  }
 
}
if (currentMenu==2)
{
  Blynk.setProperty(V1,"labels","L EC","U EC","T EC","Back");
  Blynk.syncVirtual(V1);
  Serial.println("EC selected");
  int MenuIndexID=param.asInt();
 
  if (MenuIndexID==1)
  {
    Serial.println("L EC selected");
  }
  else if (MenuIndexID==2){
    Serial.println("U EC selected");
  }
  else if (MenuIndexID==3){
    Serial.println("T EC selected");
  }
  else {
    currentMenu=0;
   
  }
}
else 
{
  Blynk.setProperty(V1,"labels","L ASE","U ASE","T ASE","Back");
  Blynk.syncVirtual(V1);
  Serial.println("ASE selected");
  int MenuIndexID=param.asInt();
  
  if (MenuIndexID==1)
  {
    Serial.println("L ASE selected");
  }
  else if (MenuIndexID==2){
    Serial.println("U ASE selected");
  }
  else if (MenuIndexID==3){
    Serial.println("T ASE selected");
  }
  else{
    currentMenu=0;
  }
}
}
  
 
void setup()
{
  // Debug console
  Serial.begin(9600);

  Blynk.begin(auth, ssidblynk, passblynk);
 
  }

void loop()
{
  Blynk.run();

}

It’s not surprising that things are loping.
Blynk.syncVirtual(V1); causes the BLYNK_WRITE(V1) callback to fire, so your pr5ocessing sstarts allo over again and any code after Blynk.syncVirtual(V1); is ignored.

Also, you’re still doing this sort of thing:

without re-loading the Menu 0 labels.

I finaslly gave-up trying to explain, and re-wrote the code for you…

#include <BlynkSimpleEsp8266.h>
#include <ESP8266WiFi.h>

char auth[] = "REDACTED";
char ssidblynk[] = "REDACTED";
char passblynk[] = "REDACTED";

WidgetLCD lcd(V2);

int currentMenu; // Used to track which menu is in use
int MenuIndexID; // Used to track which menu item has been selected in the current menu


BLYNK_WRITE(V1)
{
  MenuIndexID=param.asInt(); // Find-out which menu item was selected
  
  if (currentMenu==0)
  {
    Serial.println("Menu 0 in use");
 
    if (MenuIndexID==1)
    {
      Serial.println("Menu 0, Item 1 selected - Switching to Menu 1");
      Blynk.setProperty(V1,"labels","Menu 1 - Item 1","Menu 1 - Item 2","Menu 1 - Item 3", "Back");
      currentMenu=1;
      Blynk.virtualWrite(V1,1); // Select the first menu item
    }
    else if (MenuIndexID==2)
    {
      Serial.println("Menu 0, Item 2 selected - Switching to Menu 2");
      Blynk.setProperty(V1,"labels","Menu 2 - Item 1","Menu 2 - Item 2","Menu 2 - Item 3", "Back");
      currentMenu=2;
      Blynk.virtualWrite(V1,1); // Select the first menu item   
    }
    else if (MenuIndexID==3)
    {
      Serial.println("Menu 0, Item 3 selected - Switching to Menu 3");
      Blynk.setProperty(V1,"labels","Menu 3 - Item 1","Menu 3 - Item 2","Menu 3 - Item 3", "Back");
      currentMenu=3;
      Blynk.virtualWrite(V1,1); // Select the first menu item
    }
  }

  if (currentMenu==1)
  {
    Serial.println("Menu 1 in use");
   
    if (MenuIndexID==1)
    {
      Serial.println("Menu 1, Item 1 selected - Do some processing here...");
    }
    else if (MenuIndexID==2)
    {
      Serial.println("Menu 1, Item 2 selected - Do some processing here...");
    }
    else if (MenuIndexID==3)
    {
      Serial.println("Menu 1, Item 3 selected - Do some processing here...");
    }
    else if (MenuIndexID==4) // Back
    {
      Serial.println("Menu 1, Item 4 selected - Going back to Menu 0");
      set_Menu0_labels();      
    }
  }
  
  if (currentMenu==2)
  {
    Serial.println("Menu 2 in use");
   
    if (MenuIndexID==1)
    {
      Serial.println("Menu 2, Item 1 selected - Do some processing here...");
    }
    else if (MenuIndexID==2)
    {
      Serial.println("Menu 2, Item 2 selected - Do some processing here...");
    }
    else if (MenuIndexID==3)
    {
      Serial.println("Menu 2, Item 3 selected - Do some processing here...");
    }
    else if (MenuIndexID==4) // Back
    {
      Serial.println("Menu 2, Item 4 selected - Going back to Menu 0");
      set_Menu0_labels();      
    }
  }

  if (currentMenu==3)
  {
    Serial.println("Menu 3 in use");
   
    if (MenuIndexID==1)
    {
      Serial.println("Menu 3, Item 1 selected - Do some processing here...");
    }
    else if (MenuIndexID==2)
    {
      Serial.println("Menu 3, Item 2 selected - Do some processing here...");
    }
    else if (MenuIndexID==3)
    {
      Serial.println("Menu 3, Item 3 selected - Do some processing here...");
    }
    else if (MenuIndexID==4) // Back
    {
      Serial.println("Menu 3, Item 4 selected - Going back to Menu 0");
      set_Menu0_labels();      
    }
  }
}


void set_Menu0_labels()
{
  // Set the menu back to it's Menu 0 defaults
  // Doing this means that you only need to edit/define the Menu 0 labels on one location within the cdode 
  Blynk.setProperty(V1,"labels","Menu 0 - Show sub-menu 1","Menu 0 - Show sub-menu 2","Menu 0 - Show sub-menu 3");
  currentMenu=0;
  Blynk.virtualWrite(V1,1); // Select the first menu item
}


BLYNK_CONNECTED()
{
  // This code runs when the ESP first connects to Blynk, or after a re-conection
  // Call the function to set the menu to it's "Menu 0" defaults
  set_Menu0_labels();
}


void setup()
{
  // Debug console
  Serial.begin(9600);
  Blynk.begin(auth, ssidblynk, passblynk);
}


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

Please take the time to study the code and work-out how it works.

The only slightly strange bit is this:

  Blynk.virtualWrite(V1,1); // Select the first menu item

Which is in there to effectively set the selected MenuIndexID back to 1, so that if you select item 3 in menu 0 then item 3 isn’t still selected in menu 3 when its displayed.

As you can see, it’s getting quite mess from a code repetition point of view using if statements.

Pete.

1 Like

Thanks for your help.
I’ve made a declaration of global variables already as you mentioned in your previous post. It caused me errors Error compiling for esp8266, but now and after cleaning up my libraries, the sketch works great.
Thanks again, Pete.
The problem was solved

1 Like