/*
The Program is use to connnect to blynk local server behind NAT router.
to fullfill the task we need to use ngrok agent installed behind NAT router.
in this case we run the ngrok agent on the smartphone, running userland
ubuntu linux. The blynk local server also run on the same machine.
There for we only need to forward public tcp NGROK tunnel to port 8080 on
local host "localhost:8080".
When the ngrok agent run, we could parse the information of public url
(including the associated port) from ngrok-api. To accomplished the task
we have to create api-key on the ngrok dashboard.
with WiFi.h and HTTPClient.h library we could make https request, due https
communication we have to provide also root_ca which is grabbed from browser.
The response stream of GetRequest from the https://api.ngrok.com/tunnel, we deserialize
to json static documment, Running "for loop" for jsonObject tunnel, we
search the doc tunnel as array with keyname forwards_to == "localhost:8080"
the we save public_url.
We need to split the public_url to 2 variable
- hostname
- port
both information we use to begin blynk instance
Blynk.begin(auth,ssid,password,hostname,port)
This way we could connect to blynk localserver behind NAT firewall.
to use the code you will need
library :
1) see the library section
2) blynk localserver
3) ngrok agent running on the same machine as the blynk local server
4) blynk auth token
5) ngrok api-key : you could create on dashboard of ngrok website
ApaiTu : https://www.youtube.com/channel/UChBQyf27VmOEk8uWdQYuX-Q
thanks for :J-M-L
Jackson
who's pointed me, how the arduinojson library work.
https://forum.arduino.cc/t/parse-value-from-arduino-json/1016639
*/
#define BLYNK_PRINT Serial
#include <BlynkSimpleEsp32.h>
#include <ESP32Servo.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
Servo myservo;
int servoPin = 18;
int valBlynk;
char auth[] = "Blynk-Auth-Token";
const char* ssid = "Wokwi-GUEST";
const char* password = "";
String blynkHost;
int blynkPort =0;
void setup() {
Serial.begin(115200);
delay(1000);
WiFi.begin(ssid, password);
Serial.print("Connecting to : ");
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println(ssid);
Serial.println("======================");
httpgetngrok();
Serial.println("Matikan WiFi");
WiFi.disconnect();
blynkServo();
}
const char* root_ca= \
"-----BEGIN CERTIFICATE-----\n" \
"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\n" \
"-----END CERTIFICATE-----\n" ;
void httpgetngrok() {
StaticJsonDocument<2048> doc;
String payload;
String blynklocalserver;
if ((WiFi.status() == WL_CONNECTED)) { //Check the current connection status
Serial.println("get https://api.ngrok.com/tunnels");
HTTPClient http;
http.begin("https://api.ngrok.com/tunnels", root_ca); //Specify the URL and certificate
http.addHeader("authorization", "Bearer {API-KEY}");
http.addHeader("ngrok-version", "2");
int httpCode = http.GET(); //Make the request
if (httpCode > 0) { //Check for the returning code
payload = http.getString();
Serial.println(httpCode);
Serial.println(payload);
}
else {
Serial.println("Error on HTTP request");
forceRestart();
}
Serial.println("+++++++++++++++++++++++++++++++++++++++++++");
DeserializationError error = deserializeJson(doc, payload);
if (error) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.c_str());
forceRestart();
} else {
Serial.println(F("Serialized Payload"));
serializeJsonPretty(doc, Serial);
}
Serial.println("+++++++++++++++++++++++++++++++++++++++++++");
for (JsonObject tunnels : doc["tunnels"].as<JsonArray>()) {
const char* forwards_to = tunnels["forwards_to"];
const char* public_url = tunnels["public_url"];
//const char* age = animal["age"];
//Serial.println(forwards_to);
//Serial.println(public_url);
if (strcmp(forwards_to, "localhost:8080") == 0) { // we found it
Serial.println("=====================================");
Serial.println("ketemu public_url nya blynk local Server");
blynklocalserver = String(public_url);
Serial.println(blynklocalserver);
Serial.println("=====================================");
}
}
int index = blynklocalserver.indexOf(':');
int lastindex = blynklocalserver.lastIndexOf(':');
int length = blynklocalserver.length();
String portblynk = blynklocalserver.substring(lastindex +1,length);
blynkPort = portblynk.toInt();
blynkHost = blynklocalserver.substring(index + 3, lastindex);
Serial.println("index\t\t: " + String(index));
Serial.println("lastindex\t: " + String(lastindex));
Serial.println("Blynk Host\t: " + String(blynkHost));
Serial.println("Blynk Port\t: " + String(blynkPort));
delay(10000);
http.end(); //Free the resources
if(!blynkPort) {
Serial.println("NGrok Mati...restart");
delay(2000);
forceRestart();
}
}
}
BLYNK_WRITE(V0)
{
valBlynk = param.asInt();
}
void blynkServo(){
Serial.println("Blynk.begin......");
Blynk.begin(auth,ssid,"",blynkHost.c_str(),blynkPort);
// Allow allocation of all timers
ESP32PWM::allocateTimer(0);
ESP32PWM::allocateTimer(1);
ESP32PWM::allocateTimer(2);
ESP32PWM::allocateTimer(3);
myservo.setPeriodHertz(50);
myservo.attach(servoPin, 500, 2400);
}
void forceRestart(){
Serial.println("Restart.....");
//pinMode(34,OUTPUT);
//digitalWrite(34,LOW);
ESP.restart();
}
void loop(){
Blynk.run();
myservo.write(valBlynk);
delay(200);
}