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