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!