Skip to content

Commit

Permalink
Changed API to simplify the usage and added example for storing devic…
Browse files Browse the repository at this point in the history
…e credentials on SPIFFS
  • Loading branch information
elpinjo committed Nov 4, 2020
1 parent aaa67a8 commit 5ed7afb
Show file tree
Hide file tree
Showing 5 changed files with 272 additions and 66 deletions.
193 changes: 193 additions & 0 deletions examples/RetrieveAndStoreCredentials/RetrieveAndStoreCredentials.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
#include <CumulocityClient.h>
#ifdef ESP8266
#include <ESP8266WiFi.h>
#else //ESP32
#include <WiFi.h>
#endif
#include "FS.h"
#include "SPIFFS.h"

/* You only need to format SPIFFS the first time you run a
test or else use the SPIFFS plugin to create a partition
https://github.com/me-no-dev/arduino-esp32fs-plugin */
#define FORMAT_SPIFFS_IF_FAILED true
#define CREDENTIALS_FILE "/credentials.txt"

const char* ssid = "....";
const char* wifiPassword = ".....";
char* host = "xxx.cumulocity.com";
char* username = "...."; //bootstrap credentials can be requested through support
char* c8yPassword = "....";
char* tenant = "....";
char clientId[20];
bool storedCredentials = false;

WiFiClient wifiClient;
CumulocityClient c8yClient(wifiClient, clientId);

//Serial Number taken from the ESP32, not tested on ESP8266
void getSerialNumber() {

uint64_t chipid = ESP.getEfuseMac();
uint16_t chip = (uint16_t)(chipid >> 32);

snprintf(clientId, 19, "ESP32-%04X%08X", chip, (uint32_t)chipid);

Serial.printf("Serial Number is: %s\n", clientId);
}

//connect to a WiFi access point
void connectWifi() {
WiFi.begin(ssid, wifiPassword);

Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");

}
Serial.println("connected to wifi");
}

//read device credentials from the SPIFFS filesystem
void readCredentials(fs::FS &fs, const char *path) {
Serial.printf("Reading file: %s\r\n", path);

char buffer[4096];

File file = fs.open(path, FILE_READ);
if (!file || file.isDirectory()) {
Serial.println("- failed to read the file");
return;
}

int length = 0;
while(file.available()){
char c = file.read();
buffer[length++] = c;
}
buffer[length] = '\0';

tenant = strtok(buffer, "\n");
Serial.printf("Retrieved tenant: %s\n", tenant);

username = strtok(NULL, "\n");
Serial.printf("Retrieved user: %s\n", username);

c8yPassword = strtok(NULL, "\n");

if (tenant != NULL && username != NULL && c8yPassword != NULL) {
Serial.printf("found credentials for %s, %s\n", tenant, username);
storedCredentials = true;
}

file.close();
}

//write data to a file
void writeFile(fs::FS &fs, const char * path, const char * message){
Serial.printf("Writing file: %s\r\n", path);

File file = fs.open(path, FILE_WRITE);
if(!file){
Serial.println("- failed to open file for writing");
return;
}
if(file.print(message)){
Serial.println("- file written");
} else {
Serial.println("- write failed");
}
file.close();
}

//add data to a file
void appendFile(fs::FS &fs, const char * path, const char * message){
Serial.printf("Appending to file: %s\r\n", path);

File file = fs.open(path, FILE_APPEND);
if(!file){
Serial.println("- failed to open file for appending");
return;
}
if(file.print(message)){
Serial.println("- message appended");
} else {
Serial.println("- append failed");
}
file.close();
}

// store retrieved credentials to file
void storeCredentials() {

Credentials myCredentials = c8yClient.getCredentials();

Serial.printf("Writing credentials %s/%s to file", myCredentials.tenant, myCredentials.username);

writeFile(SPIFFS, CREDENTIALS_FILE, myCredentials.tenant);
appendFile(SPIFFS, CREDENTIALS_FILE, "\n");
appendFile(SPIFFS, CREDENTIALS_FILE, myCredentials.username);
appendFile(SPIFFS, CREDENTIALS_FILE, "\n");
appendFile(SPIFFS, CREDENTIALS_FILE, myCredentials.password);
appendFile(SPIFFS, CREDENTIALS_FILE, "\n");

Serial.println("Credentials stored");
}

//make a connection to cumulocity
void connectC8Y() {

c8yClient.connect(host, tenant, username, c8yPassword);

Serial.println("Retrieving device credentials");

if (!storedCredentials) {
c8yClient.retrieveDeviceCredentials();
while (!c8yClient.checkCredentialsReceived()) {
Serial.print("#");
delay(1000);
}

Serial.println("Reconnecting to Cumulocity");

c8yClient.disconnect();
c8yClient.reconnect();
}
}

//============================================================================
// Setup and Loop methods
//============================================================================

void setup() {

Serial.begin(115200);

connectWifi();

getSerialNumber();

if(!SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED)){
Serial.println("SPIFFS Mount Failed");
return;
}

readCredentials(SPIFFS, CREDENTIALS_FILE);

connectC8Y();

if (!storedCredentials) {
storeCredentials();
}

c8yClient.registerDevice(clientId, "c8y_esp32");

}

void loop() {

delay(1000);
c8yClient.loop();

}
25 changes: 7 additions & 18 deletions examples/SendMeasurement/SendMeasurement.ino
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,14 @@
const char* ssid = "........";
const char* wifiPassword = "........";
const char* host = "xxx.cumulocity.com";
char* username = "........";
char* c8yPassword = "........";
char* tenant = "........";
char* username = "........"; // fixed credentials can be registered in the Administration section
char* c8yPassword = "........"; // create a user in usermanagement with the "device"role and fill the credentials here
char* tenant = "........"; //tenant ID can be found by clicking on your name in the top right corner of Cumulocity
const char* clientId = "........."; //Should be a unique identifier for this device, e.g. IMEI, MAC address or SerialNumber
//uint64_t chipid = ESP.getEfuseMac();

WiFiClient wifiClient;
PubSubClient pubSubClient(host, 1883, wifiClient);
CumulocityClient c8yClient(pubSubClient, tenant, username, c8yPassword, clientId);
CumulocityClient c8yClient(wifiClient, clientId);

void setup() {

Expand All @@ -31,26 +30,16 @@ void setup() {
}
Serial.println("connected to wifi");

c8yClient.connect();
c8yClient.connect(host, tenant, username, c8yPassword);

Serial.println("Retrieving device credentials");

c8yClient.retrieveDeviceCredentials();
while (!c8yClient.checkCredentialsReceived()) {
Serial.print("#");
delay(1000);
}

c8yClient.disconnect();
c8yClient.connect();

c8yClient.registerDevice("ESP32 - Misja", "c8y_esp32");
c8yClient.registerDevice(clientId, "c8y_esp32");

}

void loop() {

delay(1000);
c8yClient.loop();
c8yClient.createMeasurement("Temperature", "T", "20.5", "*C");

}
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=Cumulocity IoT client
version=0.0.4
version=0.0.5
author=Misja Heuveling <misja.heuveling@softwareag.com>
maintainer=Misja Heuveling <misja.heuveling@softwareag.com>
sentence=A client library to connect your Arduino to Cumulocity IoT cloud over MQTT.
Expand Down
72 changes: 47 additions & 25 deletions src/CumulocityClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,58 @@
#include <stdlib.h>
#include <string.h>

CumulocityClient::CumulocityClient(PubSubClient client, char* tenant, char* user, char* password, const char* deviceId) {
CumulocityClient::CumulocityClient(Client& networkClient, const char* deviceId) {

Serial.printf("CumulocityClient(%s, %s, %s)\n", tenant, user, deviceId);
Serial.printf("CumulocityClient(%s)\n", deviceId);

_client = client;
_deviceId = deviceId;
this->_client = PubSubClient(networkClient);
this->_deviceId = deviceId;
this->_client.setKeepAlive(_keepAlive);
}

bool CumulocityClient::reconnect() {

if (_credentials.tenant != NULL && _credentials.username != NULL && _credentials.password != NULL) {
return connectClient();
} else {
return false;
}
}

bool CumulocityClient::connect(char* host, char* tenant, char* user, char* password) {

Serial.printf("connect(%s,%s,%s)\n", host, tenant, user);

_host = host;
_credentials.tenant = tenant;
_credentials.username = user;
_credentials.password = password;

_client.setKeepAlive(_keepAlive);
}
String myClientId = "d:";
myClientId += _deviceId;
_clientId = myClientId.c_str();

bool CumulocityClient::connect() {

Serial.println("connect()");
_clientId = (char*) malloc(strlen(_deviceId) +3);
strcpy(_clientId, "d:");
_clientId = strcat(_clientId, _deviceId);
_client.setServer(_host, 1883);

return connectClient();

}

bool CumulocityClient::connect(char* defaultTemplate) {
bool CumulocityClient::connect(char* host, char* tenant, char* user, char* password, char* defaultTemplate) {

_host = host;
_credentials.tenant = tenant;
_credentials.username = user;
_credentials.password = password;

String myClientId = "d:";
myClientId += _deviceId;
myClientId += ":";
myClientId += defaultTemplate;
_clientId = myClientId.c_str();

_client.setServer(_host, 1883);

_clientId = (char *) malloc(strlen(_deviceId) + strlen(defaultTemplate) + 4);
sprintf(_clientId, "d:%s:%s", _deviceId, defaultTemplate);
return connectClient();

}
Expand All @@ -46,31 +69,30 @@ bool CumulocityClient::connectClient() {
}
);

char user[512];// = (char*) malloc(strlen(_credentials.tenant) + strlen(_credentials.username) + 2);

sprintf(user, "%s/%s",_credentials.tenant, _credentials.username);

bool success = _client.connect(_clientId, user, _credentials.password, "s/us", 0, false, "400,c8y_ConnectionEvent,\"Connections lost.\"", true);
String user = _credentials.tenant;
user += "/";
user += _credentials.username;

bool success =
_client.connect(_clientId, user.c_str(), _credentials.password, "s/us", 0,
false, "400,c8y_ConnectionEvent,\"Connections lost.\"", true);

if (!success) {

Serial.print("Unable to connect to Cumulocity as ");
Serial.println(user);
Serial.println(_client.state());
} else {
Serial.println("Connected to cumulocity.");
}

//free(user);
//Serial.println("Freed the user string");

return success;
}

void CumulocityClient::disconnect() {

Serial.print("disconnect()");
_client.disconnect();
free(_clientId);
}

void CumulocityClient::retrieveDeviceCredentials() {
Expand Down Expand Up @@ -127,7 +149,7 @@ void CumulocityClient::loop() {
bool myConnected = _client.loop();

if (!myConnected) {
connect();
reconnect();
}
}

Expand Down

0 comments on commit 5ed7afb

Please sign in to comment.