BLYNK
BLYNK.IO       📲 GETTING STARTED       📗 DOCS       ❓HELP CENTER       👉 SKETCH BUILDER

Controlling Multiple Devices with One Project/Dashboard

Before switching to Blynk 2.0 I used Blynk 1.0 to control multiple ESP32-CAM modules at the same time with 1 app. I could also just use the device selector when I needed to control a single device.

Is there any way to control all of the devices in a project at the same time with the mobile dashboard?

If this feature isn’t available in Blynk 2.0, then it should be added. This is honestly the main feature I needed from Blynk 2.0.

My project will eventually have up to 256 unique devices, but if this isn’t a feature or one that can be implemented within the next 2 months then I won’t be able to continue to use Blynk 2.0.

2 Likes

You can use automation.

You should read this…

Pete.

I’m going to be using up to 256 devices. While this may work, it certainly doesn’t scale well and would require a lot of work.

Not really, it’s so simple, and no code required.

@John93 If I understand what you are suggesting correctly, it would look something like this. If I wanted to scale this to 256 devices that’s a lot of actions and not something I would ever expect a typical user to do.

(C1 being Camera 1 and C2 being Camera 2)

One dashboard to work with multiple devices is not ready yet and will not be ready in 2 months. It’s planned for Q2 2022

2 Likes

What I meant was that I wanted one button in the mobile dashboard to send a signal to the same virtual pin on all of my different devices. This was standard in Blynk 1.0, but doesn’t appear to be the case in 2.0.

Thank you Pavel. That is what I needed to know.

It’s still not clear what was your project set up with Blynk 1.0

Have you used tags?

I believe with a button and the device selector widget. On the button settings set the device to device selector. Then you could just select the device you wanted to control with the button using the device selector.

I was using the app to control a camera swarm. I was using a tag that included all of the devices.

Like this:

Strange. I do not see an “all” option on my button settings.

Are you using Android or Apple?

I created the tag and called it “All” and added all of my devices to it. On the Blynk 1.0 mobile app for Android.

2 Likes

It is amazing the amount of features and capabilities BLYNK 1.0 had. Most of which I didn’t even realize were there. Fingers crossed that BLYNK 2.0 gets to this level some day. You would think that most of these features would be easily carried over from the old to the new, but as someone who has no idea how all of this BLYNK magic works, I guess it is not so simple.

1 Like

Hello @npsantini

I am successfully using Blynk HTTP/HTTPS Get and Update to pull data from multiple devices, to control them, and to know when they’re offline. I have a ‘dashboard’ or master Blynk Device which presents information from multiple sensors, each of which is a separate Blynk Device. In another application, I am controlling multiple SONOFF-type devices from a single control panel, again using HTTP/S Get and Update.

In general, I use a Blynk HTTP Get to extract a reading from a sensor or switch Blynk Device.
In general, I use a Blynk HTTP/S Update to change the state of a switch or sensor Blynk Device.
In general, I have each of the subordinate Blynk Devices check in to the master/command/dashboard Blynk Device using a Blynk HTTP/S to let the master know the subordinate devices are alive.

I would be happy share code or explain further with the community if interested.

While some of the ‘newness’ of Blynk IoT has been maddening, I absolutely love the power of their server-side datastream management.

Hope this is helpful.

1 Like

This is so nice.
Just add another device to project and add it to the tag. Voila - the button now ALSO executes the command to this device.

1 Like

I would definitely be interested in seeing that code if you don’t mind sharing it.

I’d suggest that you start reading here…

and carry-on down that topic until you understand how these functions are being used and the variations on how that can be implemented.

You can then choose the best option for your use-case.

Note that the appropriate HTTP(S) client libraries work well of you’re using a NodeMCU or ESP32, but if you’re trying to use an Arduino + ESP-01 then you’ll need to do some additional work to get it working correctly (if that’s even possible).

Pete.

Good advice, as always, from @PeteKnight Thank you for help you have given me.

Responding to your request for code, @npsantini

Updated 13 Oct 2021 after error checking.

This is long. Hope it is helpful to you. Took me a while to get HTTP to work routinely for me.
Feel free to ask for clarification, point out errors.

I have two-way HTTP communications between my master/dashboard and my sensors/switches. My two primary applications are a home sensor network and a light/motor timer and control network (mostly SONOFFs). In general, my master or dashboard is an ESP32 and my sensors and switches are ESP8266s or SONOFFs. I’m on Windows using the Arduino IDE. HTTPS takes too long (several seconds) with the libraries I use on ESP32/8266, so I default to HTTP. Too bad. It works, though.

I use the HTTP(S) Get/Update Datastream Value capability outlined in Blynk’s new doc, referenced below. For the sensor network, I GET the remote sensor readings from the Datastreams the sensors already use locally to display their readings. Very straightforward. For the switches, I UPDATE the switch setting Datastreams when turning things on or off from the dashboard, and GET Datastream Values them when asking what each remote switch’s position is now. Code for the Blynk Get/Update Datastream Value is below.

Here’s the Blynk.io doc.
Get Datastream Value - Blynk Documentation
Update Datastream Value - Blynk Documentation

#includes and #defines needed for any HTTP use on ESP8266/32

// This sketch uses an HTTP client to get Blynk datastreams from multiple sensors, to message IFTTT, to send email
#if ESP32
  #include <HTTPClient.h>
#elif ESP8266
  #include <WiFiClient.h>
  #include <ESP8266HTTPClient.h>
#endif
#define HTTP_CODE_OK 200           // Good HTTP return code

General-purpose Blynk HTTP Get and Update Datastreams routines

String authcode = "Blynk_authcode_for_remote_device"; 
String onORoffString; 
int vPin; 

void demo(){
  // Example UPDATE call to general BlynkGetPutBridge using HTTP
  if ( BlynkGetPutBridge ( "update", authcode, vPin, onORoffString ) )
  { 
    Serial.println ( "sendOnOffControlToSONOFF succcess" );
  } 
  else 
  { 
    Serial.println ( "sendOnOffControlToSONOFF failure" ); 
  }
}


    // Generalized Blynk Get/Put (Update) Bridge code
    // GET or UPDATE info in another Blynk Datastream
    // Blynk has pretty good doc on this...
    // https://docs.blynk.io/en/blynk.cloud/update-datastream-value
    bool BlynkGetPutBridge ( const String& requestType, const String& BlynkAuthcode, const int& BlynkDatastream, String &requestValue ) 
    {
      // requestType = "get" or "update" 
      // String BlynkAuthcode = Blynk authcode of device we are writing TO
      // int BlynkDatastream = Blynk Datastream we are writing TO
      // String requestValue = value to write into or read from external BlynkDatastream 
      // example: String value= 267.8; BlynkGetPutBridge ( "update", "authcode", V6, value )
      // example: String value;        BlynkGetPutBridge ( "get", "authcode", V6, value ) )
      
      // returns true or false on success or failure
      // example if ( ! BlynkGetPutBridge ( "update", "authcode", V6, value ) ) Serial.println ( "Error" );

      String returnedValue; // temporary working String
      
      if ( requestType != "get" && requestType != "update" ) 
      {
        Serial.print ( "BlynkGetPutBridge has BAD requestType = " ); Serial.println ( requestType );
        return false; 
      }
      
      Serial.print ( "\nBlynkGetPutBridge called a \"" ); Serial.print ( requestType ); 
      Serial.print ( "\" on BlynkDatastream V" );         Serial.print ( BlynkDatastream ); 
      //Serial.print (  " on device with authcode " );      Serial.print ( BlynkAuthcode ); 

      if ( requestType == "update" ) { Serial.print (  " with update data = " ); Serial.println ( requestValue ); }
      else { Serial.println(); }

      // Set up an HTTP client object for the IFTTT POST 
    #if ESP32
      HTTPClient temporaryHTTPclient;  
    #elif ESP8266
      WiFiClient temporaryWiFiClient; 
      HTTPClient temporaryHTTPclient;  
    #endif

      // Blynk datastream get and update BOTH use HTTP.GET and a single request string
      // Server name URL with get or update (put) information
      // Format: http://BlynkserverURL/external/api/get-or-update?token=authcode&dataStreamId=value
      String BlynkGetRequest = "http://" + String ( MY_BLYNK_SERVER ) + "/external/api/";
      
      BlynkGetRequest = BlynkGetRequest + requestType; // add "get" or "update"
      
      // Blynk's GET payload for a "get"     is "token=authcode&dataStreamId"
      BlynkGetRequest = BlynkGetRequest + "?token=" + BlynkAuthcode       // Authcode of device to be updated
                                        + "&v"      + String ( BlynkDatastream );    // Virtual pin to update
                   
      // Blynk's HTTP payload for an "update" is "token=authcode&dataStreamId=value"
      if ( requestType == "update" ) 
      {
        // Get rid of any spaces in the passed parameter (without altering the passed parameter) 
        String passedString = requestValue; 
        passedString.replace ( " ", "%20" ); 
        BlynkGetRequest = BlynkGetRequest + "=" + String ( passedString ); // value to PUT (update)
      }

      //Serial.print ( " BlynkGetRequest <" ); Serial.print ( BlynkGetRequest ); Serial.println ( ">" ); 

    #if ESP32
      temporaryHTTPclient.begin ( BlynkGetRequest );  // Blynk GET wants the URL AND request
    #elif ESP8266
      temporaryHTTPclient.begin ( temporaryWiFiClient, BlynkGetRequest );  // Blynk GET wants the URL AND request
    #endif

      //temporaryHTTPclient.addHeader ( "Content-Type", "text/plain" ); // both seem to work fine
      temporaryHTTPclient.addHeader ( "Content-Type", "application/x-www-form-urlencoded" );

      // Execute the HTTP.GET containing the "get" or "updae" request, get a return code
      int BlynkAPIcallReturnCode = temporaryHTTPclient.GET ();         // use GET to send the request to Blynk
      
      Serial.print ( "  Blynk API return code: " ); Serial.println ( BlynkAPIcallReturnCode ); 
      if ( BlynkAPIcallReturnCode > 0 ) //Check the returning code (200 is AOK, anything > 0 should get a response)
      {
        returnedValue = temporaryHTTPclient.getString();   //Get the request response payload
        //Serial.println ( ", response string: <" + returnedValue + ">" );  
      }
      else 
      {
        Serial.println ( " failed" ); 
      }

      // Close the connection
      temporaryHTTPclient.end(); 

      // Load up the return variable on a "get" 
      if ( requestType == "get" ) requestValue = returnedValue; 
      
      if ( BlynkAPIcallReturnCode == HTTP_CODE_OK ) return true; else return false;
      
    } // end BlynkGetPutBridge

Here’s a specific version of this HTTP Get for reading a temperature from remote sensor’s Datastream.

#define MY_BLYNK_SERVER  "blynk.cloud" // or whatever works for you
// https://docs.blynk.io/en/blynk.cloud/get-datastream-value

// Example call to this routine
// sensorBlynkAuthcode[sensor], sensorDatastream[sensor] have Blynk device authcodes and returned sensor readings


// HTTP Get example request to get sensor reading
float returnedValue = getBlynkDatastreamInfo ( sensorBlynkAuthcode[sensor], sensorDatastream[sensor] );



// General utility to execute HTTP Get calls to return a float
float getBlynkDatastreamInfo ( const String& BlynkAuthcode, int datastream ) 
{
  // String BlynkAuthcode = Blynk authcode of device we are getting data FROM
  // int datastream = Blynk Datastream we are getting data FROM
  // example float value = getBlynkDatastreamInfo ( "authcode", V6 )
  //         if ( value == -123.45 ) Serial.println ( "Error" );  
  
  float returnedValue = -123.45; // default error value

  //Serial.print ( "\ngetBlynkDatastreamInfo called on datastream V" ); Serial.print ( datastream ); 
  //Serial.print (  " on device with authcode " ); Serial.println ( BlynkAuthcode ); 

  // Set up an HTTP client object for the Blynk get 
  HTTPClient getBlynkHTTPclient;  
  
  // Server name URL
  String BlynkGetServerName = "http://" + String ( MY_BLYNK_SERVER ) + "/external/api/get";

  // Blynk's GET payload for getting data is "?token={token}&V8"
  String BlynkRequest = "?&token=" + String ( BlynkAuthcode ) + "&v" + String ( datastream ); 

  // Blynk datastream get uses GET and a single request string
  String fullRequest = BlynkGetServerName + BlynkRequest; 
  
  //Serial.print ( " BlynkGetServerName <" ); Serial.print ( BlynkGetServerName ); Serial.println ( ">" ); 
  //Serial.print ( "  BlynkRequest     <" ); Serial.print ( BlynkRequest ); Serial.println ( ">" ); 
  //Serial.print ( "  fullRequest is   <" ); Serial.print ( fullRequest ); Serial.println ( ">" ); 

  int BlynkReturnCode; 
  long elapsed = millis();  
  
  getBlynkHTTPclient.begin ( fullRequest );  //Specify URL AND request

  BlynkReturnCode = getBlynkHTTPclient.GET();     // POST the request to Blynk

  if ( BlynkReturnCode > 0 ) //Check the returning code (200 is AOK)
  {
    String payload = getBlynkHTTPclient.getString();   //Get the request response payload
    //Serial.println ( "  response string: <" + payload + ">" );  

    if ( BlynkReturnCode == HTTP_CODE_OK )
    {
      returnedValue = payload.toFloat();   
      Serial.print ( "  Returning value: " ); Serial.println ( returnedValue ); // Serial.println();  
    }
  }
  
  getBlynkHTTPclient.end();   //Close HTTP connection

  return returnedValue;
  
} // end getBlynkDatastreamInfo

Sensing Offline remote devices
To determine and display warnings when remote devices (sensors or switches) are offline, I periodically (~20 secs.) execute a simple HTTP(S) UPDATE request from each of the remote switches and sensors to the master/dashboard. They all use the same Virtual Pin on the master/dashboard and only send an identifier of the sensor or switch. The master/dashboard, receives those Update Datastream requests using BLYNK_WRITE ( VPin ) and notes the most recent time each individual sensor or switch ‘checked in’. A timer periodically runs a routine looks to see if any of the sensors or switches have been quiet for too long. I call it checkOnTheKids.

Sensor Check-in code examples. Nearly identical code for sensors and switches.

// Sensors are numbered 0 to SENSOR_DEVICE_COUNT-1
#define SENSOR_DEVICE_COUNT 24     // number of sensors (or switches you have under control)

// The individual SONOFFs each send a signal to the same SENSOR_CHECKIN_VPIN on this device every 20 seconds or so.
#define SENSOR_CHECKIN_VPIN V99    // BLYNK_WRITE records the time stamp of the signal for each SONOFF to be compared periodically by checkOnTheKids()

// Global variables to track the recency of the remote device check ins
time_t mostRecentTimestampFromTheKids[SENSOR_DEVICE_COUNT]; // set these to zero defaults somewhere early

bool kidsMustBeAlive[SENSOR_DEVICE_COUNT]; // set these to true to get started – assume the best!



// HTTP UPDATE from the sensor or switch triggers this routine (Set as String Datastream value)
BLYNK_WRITE ( SENSOR_CHECKIN_VPIN ) // ONLY called by SONOFF devices, never by user
{
  int checkInID = param[0].asInt(); // Grab the unique ID number sent by the remote device

  Serial.print ( "\nSensor #" ); Serial.print ( checkInID ); Serial.print ( " " ); 
  Serial.println ( " CHECKING IN" );  

  time_t timeNow = now(); // must #include <TimeLib.h> time library
  if ( checkInID >= 0 && checkInID < SENSOR_DEVICE_COUNT )
  {
    // save the timestamp
    mostRecentTimestampFromTheKids[checkInID] = timeNow; 
  }
} // end BLYNK_WRITE ( SENSOR_CHECKIN_VPIN )




// This initializes the checkOnTheKids global variables, 
//  ** IF YOU USE BLYNK’S RTC, THIS CAN ONLY EXECUTE AFTER THE RTC CONNECTS **

void initializeCheckOnTheKids()
{
  Serial.print ( "\ninitializeCheckOnTheKids called... " ); 
  
  time_t timeNow = now(); 
  Serial.print ( "timenow = " ); Serial.print ( timeNow ); 
  
  for ( int device = 0; device < SENSOR_DEVICE_COUNT; device++ )
  {
    mostRecentTimestampFromTheKids[device] = timeNow; 
  }
  Serial.println ( " and exited" ); 
} // end initializeCheckOnTheKids




// checkOnTheKids called by a Timer to see if all the SONOFFs are alive or not

#define CHECK_ON_THE_KIDS_TIMEGAP 90000 // 90 seconds of no calls means device is offline

void checkOnTheKids()
{
  Serial.println ( "\n*********************************\ncheckOnTheKids called... " ); 

  time_t timeNow = now(); 

  // Check each device for a check-in timestamp that is too old.  EVERYTHING IS IN SECONDS in timelib
  for ( int device = 0; device < SENSOR_DEVICE_COUNT; device++ )
  {
    Serial.print( "   #" ); Serial.print ( device ); Serial.print ( " " ); 
    Serial.print ( " delta (sec.) " ); Serial.print ( timeNow -  mostRecentTimestampFromTheKids[device] ); 
      
    if ( timeNow -  mostRecentTimestampFromTheKids[device] < CHECK_ON_THE_KIDS_TIMEGAP ) 
    {
      Serial.println ( " -> OK " ); // Have recent signal from this sensor device - It is GOOD

      // Code here to display and set the status as GOOD

      kidsMustBeAlive[device] = true;
    }
    else 
    {
      Serial.println ( " -> no " ); // No recent signal from this sensor device - It is DOWN

      // Code here to display and set the status as OFFLINE

      kidsMustBeAlive[device] = false;
    }
  }
  Serial.println();  
  Serial.println ( "... exiting checkOnTheKids" ); 
  
} // end checkOnTheKids
1 Like