-->
Page 1 of 1

Reading a continuous flow of JSON data from a webserver

PostPosted: Sat Jul 17, 2021 8:11 am
by bgrigoriu
HI, I have a home automation system that give s on a webpage a continuous flow of data (every second) in JSON format for a dozen of measured parameters.
I would need to read them and copy in the corresponding variables.
So globally three steps:
1. Logging to server ( Digest authentication) - solved I think
2. reading String from Webpage Every second - NO IDEA HOW TO DO it and found no tutorials/examples
3. Parsing JSON and extracting data (easiest part I think)

Can anyone help with some links/opinion?

Re: Reading a continuous flow of JSON data from a webserver

PostPosted: Sun Jul 18, 2021 9:14 am
by bgrigoriu
I have advanced a little bit.
The Serviver is using SSE and thus sends a continous flow. The programs stuck when it tries to read the payload through getString.
Do anyone now if there is an SSE library for ESP8266 that allows READING an SSE thread?
Thanks for all your opinions /directions

Re: Reading a continuous flow of JSON data from a webserver

PostPosted: Wed Jul 21, 2021 6:33 am
by bgrigoriu
Hi,
I advanced a little bit more. The code is fully functional as belllow.
It runs without issues a few hours long.
As I am still in my early phases of learning, could you all please suggest corrections if any strategic errors are made or if any optimisation in terms of size/ of speed / of portability is possible.
Code: Select all
#include <ESP8266WiFi.h>

#include <ESP8266HTTPClient.h>
#include <ArduinoJson.h>

#ifndef STASSID
#define STASSID "YourSSID"
#define STAPSK  "YourNetworkpassword"
#endif

const char* ssid = STASSID;
const char* ssidPassword = STAPSK;

const char *username = "installer";
const char *password = "YourEnvoyPassword";

const char *server = "http://192.168.1.4";  // Put here the IP of your envoy
const char *uri = "/stream/meter";

float Power =0 ;
float AReal_power = 0;
float AReactive_power = 0;
float AApparent_power = 0;
float Avoltage = 0;
float Acurrent =0 ;
float pf = 0;
float freq = 0;

float BReal_power = 0;
float BReactive_power = 0;
float BApparent_power = 0;
float Bvoltage = 0;
float Bcurrent =0 ;

float CReal_power = 0;
float CReactive_power = 0;
float CApparent_power = 0;
float Cvoltage = 0;
float Ccurrent =0 ;

float tcAReal_power = 0;
float tcAReactive_power = 0;
float tcAApparent_power = 0;
float tcAvoltage = 0;
float tcAcurrent =0 ;

float tcBReal_power = 0;
float tcBReactive_power = 0;
float tcBApparent_power = 0;
float tcBvoltage = 0;
float tcBcurrent =0 ;

float tcCReal_power = 0;
float tcCReactive_power = 0;
float tcCApparent_power = 0;
float tcCvoltage = 0;
float tcCcurrent =0 ;

float Consumption = 0;
float NetPower = 0;

  WiFiClient client;
  HTTPClient http;                                 

void setup() {
 
  Serial.begin(74880);
  Serial.println("Begin");
  randomSeed(RANDOM_REG32);

  WiFi.mode(WIFI_STA);                      // define conection mode
  WiFi.begin(ssid, ssidPassword);             // initialize wifi network   
 
  while (WiFi.status() != WL_CONNECTED) {  // wait to be connected
    delay(500);
    Serial.print(".");
  }
 
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void loop() {

  Serial.print("[HTTP] begin...\n"); 
  http.begin(client, String(server) + String(uri));   // configure traged server and url

  const char *keys[] = {"WWW-Authenticate"};
  http.collectHeaders(keys, 1);

  Serial.print("[HTTP] GET...\n");                    // Starting first GET - authentication only
  // start connection and send HTTP header
 
  int httpCode = http.GET();
    if (httpCode > 0) {
      String authReq = http.header("WWW-Authenticate");
      String authorization = getDigestAuth(authReq, String(username), String(password), "GET", String(uri), 1);
      http.end();
   
      http.begin(client, String(server) + String(uri));
      http.addHeader("Authorization", authorization);

      int httpCode = http.GET();           // Second GET - Actually getting the payload here
      if (httpCode == 200) {
         WiFiClient *cl = http.getStreamPtr();
        int error = 0;
        do {
          cl->find("data: ");
          String payload = cl->readStringUntil('\n');
          error = processingJsondata(payload);
          client.flush();
        } while (error);
      } else {
            Serial.print("[HTTP] GET... failed, error: ");
            Serial.println(http.errorToString(httpCode).c_str());
        }
    } else {
          Serial.print("[HTTP] GET... failed, error: ");
          Serial.println(http.errorToString(httpCode).c_str());
      }

  http.end();
  delay(3000);
}


// Functions for Digest authorisation

String exractParam(String& authReq, const String& param, const char delimit) {
  int _begin = authReq.indexOf(param);
  if (_begin == -1) {
    return "";
  }
  return authReq.substring(_begin + param.length(), authReq.indexOf(delimit, _begin + param.length()));
}

String getCNonce(const int len) {
  static const char alphanum[] =
    "0123456789"
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    "abcdefghijklmnopqrstuvwxyz";
  String s = "";

  for (int i = 0; i < len; ++i) {
    s += alphanum[rand() % (sizeof(alphanum) - 1)];
  }

  return s;
}

String getDigestAuth(String& authReq, const String& username, const String& password, const String& method, const String& uri, unsigned int counter) {
  // extracting required parameters for RFC 2069 simpler Digest
  String realm = exractParam(authReq, "realm=\"", '"');
  String nonce = exractParam(authReq, "nonce=\"", '"');
  String cNonce = getCNonce(8);

  char nc[9];
  snprintf(nc, sizeof(nc), "%08x", counter);

  // parameters for the RFC 2617 newer Digest
  MD5Builder md5;
  md5.begin();
  md5.add(username + ":" + realm + ":" + password);  // md5 of the user:realm:user
  md5.calculate();
  String h1 = md5.toString();

  md5.begin();
  md5.add(method + ":" + uri);
  md5.calculate();
  String h2 = md5.toString();

  md5.begin();
  md5.add(h1 + ":" + nonce + ":" + String(nc) + ":" + cNonce + ":" + "auth" + ":" + h2);
  md5.calculate();
  String response = md5.toString();

  String authorization = "Digest username=\"" + username + "\", realm=\"" + realm + "\", nonce=\"" + nonce +
                         "\", uri=\"" + uri + "\", algorithm=\"MD5\", qop=auth, nc=" + String(nc) + ", cnonce=\"" + cNonce + "\", response=\"" + response + "\"";

//  Serial.println(authorization);

  return authorization;
}
// End of functions for digest authorisation
// function for displaying data is not presented