Null value appears using two consecutive method

Hello all,

I am currently using NTP library to do a project now. Here is the code.

HttpUpstream.h


//#if (defined(ARDUINO__AVR__MEGA) || defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_SAM))
//#include <avr/pgmspace.h>
//#else
//#include <pgmspace.h>
//#endif

#ifndef HttpUpstream_h
#define HttpUpstream_h

#include "Arduino.h"
#include <WiFiNINA.h>
#include "NTPClient.h"
#include "Base64.h" //Base64 shouldn't be located at library file
#include <ArduinoJson.h>
#include <string.h>

class HttpUpstreamClient{

  private:
  
  char* _clientId;
  char* _host;
  char* _base64;
  String _deviceID;
  
  void base64(char* username, char* password);

  //void obtaindeviceID(String msg);
  
  public:

  Client* _networkClient;
  
  
  HttpUpstreamClient(Client& networkClient);

  //create device with a unique device name  
  void registerDevice(char* deviceName, char* URL, char* username, char* password);

  //send a single measurement to the cloud without knowing the device ID 
  void sendMeasurement(int value, char* unit, String timestamp,char* measurementType,char* measurementname,char* URL);

  //send a single measurement to the cloud knowing the device ID
  void sendMeasurementDeviceId(int value, char* unit, String timestamp,char* measurementType,char* measurementname,char* URL,String deviceID);

  //send an alarm to the cloud without knowing the device ID 
  void sendAlarm(char* alarmType, char* alarmText, char* severity, String timestamp,char* URL);

  
  };

#endif

HttpUpstream.cpp is as following

#include "HttpUpstream.h"


HttpUpstreamClient::HttpUpstreamClient(Client& networkClient){

_networkClient = &networkClient;

  }

//Base64 encoder
void HttpUpstreamClient::base64(char* username, char* password){
  char temp[100];
  
  strcpy(temp , username);
  strcat(temp, ":");
  strcat(temp, password);
  Serial.println();
  //For debugging
  Serial.print("Information needs to be coded is:");
  Serial.println(temp);
  
  int inputStringLength = strlen(temp);
  int encodedLength = Base64.encodedLength(inputStringLength);
  char encodedString[encodedLength];
  Base64.encode(encodedString, temp, inputStringLength);
  Serial.print("Encoded string is: ");
  Serial.println(encodedString);

  if (_base64) free (_base64);
  _base64 = (char*) malloc(sizeof(char) * strlen(encodedString));
  strcpy(_base64, encodedString);
  
  Serial.print("Stored Based64 string is: ");
  Serial.println(_base64);
  }


//Register device on the cloud and obtain the device id
void HttpUpstreamClient::registerDevice(char* deviceName, char* URL, char* username, char* password){

 //Base64 encoding
 base64(username, password);

 //JSON Body
 StaticJsonDocument<100> body;
 String body2send= "";
 body["name"] = deviceName;
 body["c8y_IsDevice"]="{}";
 //serializeJsonPretty(body, Serial);  
 serializeJsonPretty(body, body2send);
 Serial.println(body2send); 

 //HTTP header
if(_networkClient->connect(URL,443)){
    Serial.println("Connected to server");
    Serial.println(_base64);
    _networkClient->println("POST /inventory/managedObjects/ HTTP/1.1");
    _networkClient->print("Host: ");
    _networkClient->println(URL);
    _networkClient->print("Authorization: Basic ");
    _networkClient->println(_base64);
    _networkClient->println("Content-Type: application/json");
    _networkClient->print("Content-Length: ");
    _networkClient->println(body2send.length());
    _networkClient->println("Accept: application/json");
    _networkClient->println();
    //client.println("Connection: close");
    _networkClient->println(body2send);  
  
    } 

   //Device ID 
   while(_deviceID.length()==0){
        String msg="";
       while(_networkClient->available()){
         char c = _networkClient->read();
         msg += c;
       }
         int start = msg.indexOf("\"id\"");
         int until = msg.indexOf("\":", start);
         int until_n = msg.indexOf("\",",until);
         if(until!= -1 && start!= -1 ){
         _deviceID = msg.substring(until+3,until_n);
         Serial.print("Device ID for ");
         Serial.print(deviceName);
         Serial.print(" is :");
         Serial.println(_deviceID);
         //Serial.println(_deviceID.length());
        }  
    
    }
  
  }

  //Send measurement value to the cloud
  //Measurement Type: c8y_Xmeasuremnt
  //Measuremnt Name: c8y_measurmentname 
  void HttpUpstreamClient::sendMeasurement(int value, char* unit, String timestamp,char* measurementType,char* measurementObjectName,char* URL){
    
    Serial.print("The measurement is sent to the device: ");
    Serial.println(_deviceID);

    StaticJsonDocument<150> root;
    //JsonObject root = body.to<JsonObject>();
    JsonObject source  = root.createNestedObject("source");
    JsonObject measurement_object  = root.createNestedObject(measurementType);
    JsonObject object  = measurement_object.createNestedObject(measurementObjectName);
    source["id"] = _deviceID;
    root["time"] = timestamp;
    root["type"] = measurementType;
    object["unit"] = unit;
    object["value"] = value;
    
    String body2send= "";
    serializeJsonPretty(root, body2send);
    Serial.println(body2send);  
      
    if(_deviceID.length()!=0){
    
    if(_networkClient->connect(URL,443)){
    Serial.println("Connected to server");
    
    _networkClient->println("POST /measurement/measurements HTTP/1.1");  
    _networkClient->print("Host: ");
    _networkClient->println(URL);
    _networkClient->print("Authorization: Basic ");
    _networkClient->println(_base64);
    _networkClient->println("Content-Type: application/json");
    _networkClient->print("Content-Length: ");
    _networkClient->println(body2send.length());
    _networkClient->println("Accept: application/json");
    _networkClient->println();
    //client.println("Connection: close");
    _networkClient->println(body2send);
    }                                                
        }
        
  }


  void HttpUpstreamClient::sendMeasurementDeviceId(int value, char* unit, String timestamp,char* measurementType,char* measurementObjectName,char* URL,String deviceID){
    
    Serial.print("The measurement is sent to the device: ");
    Serial.println(deviceID);

    StaticJsonDocument<100> root;
    //JsonObject root = body.to<JsonObject>();
    JsonObject source  = root.createNestedObject("source");
    JsonObject measurement_object  = root.createNestedObject(measurementType);
    JsonObject object  = measurement_object.createNestedObject(measurementObjectName);
    source["id"] = deviceID;
    root["time"] = timestamp;
    root["type"] = measurementType;
    object["unit"] = unit;
    object["value"] = value;
    
    String body2send= "";
    serializeJsonPretty(root, body2send);
    Serial.println(body2send);  
      
    if(deviceID.length()!=0){
    
    if(_networkClient->connect(URL,443)){
    Serial.println("Connected to server");
    
    _networkClient->println("POST /measurement/measurements HTTP/1.1");  
    _networkClient->print("Host: ");
    _networkClient->println(URL);
    _networkClient->print("Authorization: Basic ");
    _networkClient->println(_base64);
    _networkClient->println("Content-Type: application/json");
    _networkClient->print("Content-Length: ");
    _networkClient->println(body2send.length());
    _networkClient->println("Accept: application/json");
    _networkClient->println();
    //client.println("Connection: close");
    _networkClient->println(body2send);
    }                                                
        }
  }

  
  void HttpUpstreamClient::sendAlarm(char* alarmType, char* alarmText, char* severity, String timestamp,char* URL){
    
    Serial.print("The alarm is sent to the device: ");
    Serial.println(_deviceID);


    StaticJsonDocument<100> root;
    JsonObject source  = root.createNestedObject("source");
    source["id"] = _deviceID;
    root["type"] = alarmType;
    root["text"] = alarmText;
    root["severity"] = severity;
    root["time"] = timestamp;

    String body2send= "";
    serializeJsonPretty(root, body2send);
    Serial.println(body2send);

    if(_networkClient->connect(URL,443)){
    
    Serial.println("Connected to server");
    
    _networkClient->println("POST /alarm/alarms HTTP/1.1");  
    _networkClient->print("Host: ");
    _networkClient->println(URL);
    _networkClient->print("Authorization: Basic ");
    _networkClient->println(_base64);
    _networkClient->println("Content-Type: application/json");
    _networkClient->print("Content-Length: ");
    _networkClient->println(body2send.length());
    _networkClient->println("Accept: application/json");
    _networkClient->println();
    //client.println("Connection: close");
    _networkClient->println(body2send);
    
    }    

       }

     
    

TestLibrary.ino is as following:

#include "HttpUpstream.h"
#include "arduino_secrets.h" 
#include <WiFiNINA.h>



WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);
NTPClient timeClient_Alarm(ntpUDP);

WiFiSSLClient nwc;
HttpUpstreamClient clienttest(nwc);


int status = WL_IDLE_STATUS;

//Gereral para
char* deviceName ="librarytest_device_3";
char* URL = "xxxxxxx.cumulocity.com";
char* username = "xxxxxx";
char* password ="xxx";

//Measurement
char* measurement_type = "c8y_SpeedMeasurement";
char* measurement_object = "c8y_RotationSpeed";

//Alarm Type
char* alarm_Type = "c8y_HellofromArduino";
char* alarm_Text = "Hello World!";
char* Severity = "WARNING";


char ssid[] = SECRET_SSID;        // your network SSID (name)
char pass[] = SECRET_PASS;    // your network password (use for WPA, or use as key for WEP)

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);

  if (WiFi.status() == WL_NO_MODULE) {
  Serial.println("Communication with WiFi module failed!");
  // don't continue
  while (true);
  }

  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);
    
    // wait 10 seconds for connection:
    delay(6000);
  }
  Serial.println("Connected to WiFi");  

  
  timeClient.begin();
  timeClient_Alarm.begin();
  clienttest.registerDevice(deviceName,URL,username,password);
  //clienttest.sendMeasurement(5,5,"hello");
  
}

void loop() {
  // put your main code here, to run repeatedly:
 
  // from the server, read them and print them: 
   while (nwc.available()) {
   char c = nwc.read();
   //Serial.print(c);        
   }

timeClient.update();

//delay(1000);

clienttest.sendMeasurement(random(20),"rad/sec",timeClient.getFormattedDate(),measurement_type,measurement_object,URL);

if(random(20)>10){
  //Serial.println(timeClient.getFormattedDate());
clienttest.sendAlarm(alarm_Type, alarm_Text,Severity,timeClient.getFormattedDate(),URL);

}

}
     
    

Each time the timeClient.getFormattedDate() from clienttest.sendMeasurement() can be successfully triggered. However the same method from clienttest.sendAlarm() couldn't. It get a "null" as following:

The measurement is sent to the device: 2634542
{
"source": {
"id": "2634542"
},
"c8y_SpeedMeasurement": {
"c8y_RotationSpeed": {
"unit": "rad/sec",
"value": 10
}
},
"time": "2022-09-13T14:49:33Z",
"type": "c8y_SpeedMeasurement"
}
Connected to server
The alarm is sent to the device: 2634542
{
"source": {
"id": "2634542"
},
"type": "c8y_HellofromArduino",
"text": "Hello World!",
"severity": "WARNING",
"time": null
}

Then I tried with these piece of code:

clienttest.sendMeasurement(random(20),"rad/sec",timeClient.getFormattedDate(),measurement_type,measurement_object,URL);

if(random(20)>10){
  //Serial.println(timeClient.getFormattedDate());
timeClient.getFormattedDate();

}

It works and it works pretty well.

What could possibly go wrong here? Why the method timeClient.getFormattedDate() can work alone and doesn't work at all when it becomes a parameter of two consecutive method?

Thanks!

Have you tried to set a variable with the value of timeClient.getFormattedDate() and provide that as a parameter to the two routines?

Hi pylon,

I finally know what had happened now. It is the memory space reserved at StaticJsonDocument<100> root that causes the problem.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.