From 17af61d325fbc639bd6948f4312164c3401fda36 Mon Sep 17 00:00:00 2001 From: matsfunk Date: Wed, 16 Dec 2020 19:25:09 +0100 Subject: [PATCH] - added Data Foundry support to the library - added two examples for show how to use the DF supporting class - added wifi multi example --- dist/oocsi/DFDataset.cpp | 357 ++++++++++++++++++ dist/oocsi/DFDataset.h | 100 +++++ .../Entity_dataset/Entity_dataset.ino | 80 ++++ .../DataFoundry/IoT_dataset/IoT_dataset.ino | 58 +++ .../OOCSI_wifi_multi/OOCSI_wifi_multi.ino | 50 +++ src/DFDataset.cpp | 357 ++++++++++++++++++ src/DFDataset.h | 100 +++++ 7 files changed, 1102 insertions(+) create mode 100644 dist/oocsi/DFDataset.cpp create mode 100644 dist/oocsi/DFDataset.h create mode 100644 dist/oocsi/examples/DataFoundry/Entity_dataset/Entity_dataset.ino create mode 100644 dist/oocsi/examples/DataFoundry/IoT_dataset/IoT_dataset.ino create mode 100644 dist/oocsi/examples/Extras/OOCSI_wifi_multi/OOCSI_wifi_multi.ino create mode 100644 src/DFDataset.cpp create mode 100644 src/DFDataset.h diff --git a/dist/oocsi/DFDataset.cpp b/dist/oocsi/DFDataset.cpp new file mode 100644 index 0000000..4f10b87 --- /dev/null +++ b/dist/oocsi/DFDataset.cpp @@ -0,0 +1,357 @@ +/*************************************************************************** + * The DataFoundry library for the ESP32 and ESP 8266 to store and retrieve + * data from ESPs on the Data Foundry platform. + * + * Developed by Mathias Funk + **************************************************************************/ + +#include "DFDataset.h" + +/** + * @brief Constructor for creating a new DFDataset + * @note Should only be called once + * @retval A new DFDataset client + */ +DFDataset::DFDataset(const char* server, int id, const char* token) { + host = server; + dataset_id = id; + api_token = token; + logging = true; + jsonMessage.clear(); +} + +// iot datasets +void DFDataset::device(const char* device) { + device_id = device; +} + +void DFDataset::activity(const char* act) { + activity_id = act; +} + +// entity datasets +void DFDataset::id(const char* id) { + resource_id = id; +} + +void DFDataset::token(const char* token) { + resource_token = token; +} + +const char* root_ca_df = "-----BEGIN CERTIFICATE-----\n" \ + "MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/\n" \ + "MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\n" \ + "DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow\n" \ + "PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD\n" \ + "Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n" \ + "AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O\n" \ + "rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq\n" \ + "OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b\n" \ + "xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw\n" \ + "7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD\n" \ + "aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV\n" \ + "HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG\n" \ + "SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69\n" \ + "ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr\n" \ + "AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz\n" \ + "R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5\n" \ + "JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo\n" \ + "Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ\n" \ + "-----END CERTIFICATE-----"; + +bool DFDataset::logItem() { + + // check basic input data + if(host == NULL || api_token == NULL || dataset_id == 0) { + return false; + } + + // check message + String postMessage = String(); + serializeJson(jsonMessage, postMessage); + if(postMessage == NULL || postMessage == "null") { + return false; + } + + // set missing data + activity_id = activity_id != NULL ? activity_id : ""; + device_id = device_id != NULL ? device_id : ""; + + // compile address + snprintf_P(address, sizeof(address), PSTR("http://%s/datasets/ts/log/%i/%s"), host, dataset_id, activity_id); + + // do transmission + HTTPClient http; + http.begin(address/*, root_ca_df*/); + http.addHeader("Content-Type", "application/json"); + http.addHeader("api_token", api_token); + http.addHeader("source_id", device_id); + http.addHeader("device_id", device_id); + + int httpCode = http.POST(postMessage); + jsonMessage.clear(); + + http.end(); + + return httpCode == HTTP_CODE_OK; +} + +bool DFDataset::addItem() { + + // check basic input data + if(host == NULL || api_token == NULL || resource_id == NULL || dataset_id == 0) { + return false; + } + + // check message + String postMessage = String(); + serializeJson(jsonMessage, postMessage); + + // compile address + snprintf_P(address, sizeof(address), PSTR("http://%s/datasets/entity/%i/item/"), host, dataset_id); + + // set missing data + resource_token = resource_token != NULL ? resource_token : ""; + + // do transmission + HTTPClient http; + http.begin(address/*, root_ca_df*/); + http.addHeader("Content-Type", "application/json"); + http.addHeader("resource_id", resource_id); + http.addHeader("token", resource_token); + http.addHeader("api_token", api_token); + + int httpCode = http.POST(postMessage); + jsonMessage.clear(); + + http.end(); + + return httpCode == HTTP_CODE_OK; +} + +bool DFDataset::updateItem() { + + // check basic input data + if(host == NULL || api_token == NULL || resource_id == NULL || dataset_id == 0) { + return false; + } + + // check message + String postMessage = String(); + serializeJson(jsonMessage, postMessage); + + // compile address + snprintf_P(address, sizeof(address), PSTR("http://%s/datasets/entity/%i/item/"), host, dataset_id); + + // set missing data + resource_token = resource_token != NULL ? resource_token : ""; + + // do transmission + HTTPClient http; + http.begin(address/*, root_ca_df*/); + http.addHeader("Content-Type", "application/json"); + http.addHeader("resource_id", resource_id); + http.addHeader("token", resource_token); + http.addHeader("api_token", api_token); + + int httpCode = http.PUT(postMessage); + jsonMessage.clear(); + + http.end(); + + return httpCode == HTTP_CODE_OK; +} + +bool DFDataset::deleteItem() { + + // check basic input data + if(host == NULL || api_token == NULL || resource_id == NULL || dataset_id == 0) { + return false; + } + + // compile address + snprintf_P(address, sizeof(address), PSTR("http://%s/datasets/entity/%i/item/"), host, dataset_id); + + // set missing data + resource_token = resource_token != NULL ? resource_token : ""; + + // do transmission + HTTPClient http; + http.begin(address/*, root_ca_df*/); + http.addHeader("Content-Type", "application/json"); + http.addHeader("resource_id", resource_id); + http.addHeader("token", resource_token); + http.addHeader("api_token", api_token); + + int httpCode = http.sendRequest("DELETE"); + jsonMessage.clear(); + + String jsonResponse = http.getString(); + + http.end(); + + return httpCode == HTTP_CODE_OK; +} + +bool DFDataset::getItem() { + // check basic input data + if(host == NULL || api_token == NULL || resource_id == NULL || dataset_id == 0) { + return false; + } + + // compile address + snprintf_P(address, sizeof(address), PSTR("http://%s/datasets/entity/%i/item/"), host, dataset_id); + + // set missing data + resource_token = resource_token != NULL ? resource_token : ""; + + // do transmission + HTTPClient http; + http.begin(address/*, root_ca_df*/); + http.addHeader("Content-Type", "application/json"); + http.addHeader("resource_id", resource_id); + http.addHeader("token", resource_token); + http.addHeader("api_token", api_token); + + int httpCode = http.GET(); + jsonMessage.clear(); + + String jsonResponse = http.getString(); + + http.end(); + + if(jsonResponse.length() > 0) { + DeserializationError error = deserializeJson(jsonDocument, jsonResponse.c_str()); + if (error) { + print(F("Message parsing failed: ")); + println(error.c_str()); + return false; + } + return true; + } else { + return false; + } +} + +bool DFDataset::getBool(const char* key, bool standard) { + if(jsonDocument.isNull() || !jsonDocument.containsKey(key)) { + return standard; + } else { + return jsonDocument[key].as(); + } +} + +int DFDataset::getInt(const char* key, int standard) { + if(jsonDocument.isNull() || !jsonDocument.containsKey(key)) { + return standard; + } else { + return jsonDocument[key].as(); + } +} + +long DFDataset::getLong(const char* key, long standard) { + if(jsonDocument.isNull() || !jsonDocument.containsKey(key)) { + return standard; + } else { + return jsonDocument[key].as(); + } +} + +float DFDataset::getFloat(const char* key, float standard) { + if(jsonDocument.isNull() || !jsonDocument.containsKey(key)) { + return standard; + } else { + return jsonDocument[key].as(); + } +} + +String DFDataset::getString(const char* key, const char* standard) { + if(jsonDocument.isNull() || !jsonDocument.containsKey(key)) { + return standard; + } else { + return jsonDocument[key].as(); + } +} + +bool DFDataset::has(const char* key) { + return jsonDocument.containsKey(key); +} + +// function for outputting all (top-level) keys in the message as a comma-separated list +String DFDataset::keys() { + if(jsonDocument.isNull() || jsonDocument.size() == 0) { + return ""; + } + + // comma separated key list + String result = ""; + for (JsonPair p : jsonDocument.as()) { + if(result.length() > 0) { + result.concat(","); + } + result.concat(p.key().c_str()); + } + return result; +} + +// function for sending a bool to DFDataset +DFDataset DFDataset::addBool(const char* key, bool value) { + jsonMessage[key] = value; + return *this; +} + +// function for sending an int to DFDataset +DFDataset DFDataset::addInt(const char* key, int value) { + jsonMessage[key] = value; + return *this; +} + +// function for sending an int to DFDataset +DFDataset DFDataset::addLong(const char* key, long value) { + jsonMessage[key] = value; + return *this; +} + +// function for sending a float to DFDataset +DFDataset DFDataset::addFloat(const char* key, float value) { + jsonMessage[key] = value; + return *this; +} + +DFDataset DFDataset::addString(const char* key, const char* value) { + jsonMessage[key] = value; + return *this; +} + +void DFDataset::print(const String &message) { + if(logging) + Serial.print(message); +} + +void DFDataset::print(char message) { + if(logging) + Serial.print(message); +} + +void DFDataset::println() { + if(logging) + Serial.println(); +} + +void DFDataset::println(const String &message) { + if(logging) + Serial.println(message); +} + +void DFDataset::println(char message) { + if(logging) + Serial.println(message); +} + +void DFDataset::setActivityLEDPin(int ledPin) { + activityLEDPin = ledPin; +} + +void DFDataset::setLogging(bool log) { + logging = log; +} diff --git a/dist/oocsi/DFDataset.h b/dist/oocsi/DFDataset.h new file mode 100644 index 0000000..30b6dc3 --- /dev/null +++ b/dist/oocsi/DFDataset.h @@ -0,0 +1,100 @@ +/*************************************************************************** + * The DataFoundry library for the ESP32 and ESP 8266 to store and retrieve + * data from ESPs on the Data Foundry platform. + * + * Developed by Mathias Funk + **************************************************************************/ + +#ifndef DFDATASET_h +#define DFDATASET_h + +#ifdef ESP32 + #include + #include + #ifndef MSG_SIZE + #define MSG_SIZE 2048 + #endif +#else + #include + #include + #ifndef MSG_SIZE + #define MSG_SIZE 1024 + #endif +#endif +#ifndef LED_BUILTIN + #define LED_BUILTIN -1 +#endif +#include + +class DFDataset { + + public: + + // setup + DFDataset(const char* host, int id, const char* token); + + // iot datasets + void device(const char* act); + void activity(const char* act); + // entity datasets + void id(const char* act); + void token(const char* act); + + // sending data + DFDataset clear(); + DFDataset addBool(const char* key, bool value); + DFDataset addInt(const char* key, int value); + DFDataset addLong(const char* key, long value); + DFDataset addFloat(const char* key, float value); + DFDataset addString(const char* key, const char* value); + + // operations + bool logItem(); + bool addItem(); + bool updateItem(); + bool deleteItem(); + bool getItem(); + + // receiving data + bool getBool(const char* key, bool standard); + int getInt(const char* key, int standard); + long getLong(const char* key, long standard); + float getFloat(const char* key, float standard); + String getString(const char* key, const char* standard); + bool has(const char* key); + String keys(); + + // misc + void printMessage(); + void setActivityLEDPin(int ledPin); + void setLogging(bool log); + + private: + + // configuration + const char* host; + char address[200]; + const char* api_token; + const char* device_id; + const char* activity_id; + const char* resource_id; + const char* resource_token; + int dataset_id = 0; + + // data + StaticJsonDocument jsonDocument; + StaticJsonDocument jsonMessage; + String jsonMessageReceiver; + bool receivedMessage; + + // logging + int activityLEDPin; + bool logging; + void print(const String &message); + void print(char message); + void println(); + void println(const String &message); + void println(char message); +}; + +#endif diff --git a/dist/oocsi/examples/DataFoundry/Entity_dataset/Entity_dataset.ino b/dist/oocsi/examples/DataFoundry/Entity_dataset/Entity_dataset.ino new file mode 100644 index 0000000..4c295f3 --- /dev/null +++ b/dist/oocsi/examples/DataFoundry/Entity_dataset/Entity_dataset.ino @@ -0,0 +1,80 @@ +/********************************************************************* + Example of the ESP connecting to WiFi and accessing items in an + Entity dataset on the Data Foundry. + This works only with an existing account, project and dataset on + the Data Foundry (https://data.id.tue.nl) + *********************************************************************/ + +#include "DFDataset.h" + +// SSID of your Wifi network, the library currently does not support WPA2 Enterprise networks +const char* ssid = "yourssid"; +// Password of your Wifi network. +const char* password = "yourpassword"; + +// put the adress of Data Foundry here +const char* datafoundry = "data.id.tue.nl"; + +// create connection to dataset with server address, dataset id, and the access token +DFDataset entity(datafoundry, 2, "hmktGR2B9fWbOLYIzB2jrFCmXn7HVJzN/1eutNdGtnSJ1XZe"); + +// put your setup code here, to run once: +void setup() { + Serial.begin(115200); + + // establish Wifi connection + WiFi.begin(ssid, password); + Serial.println("Connecting to WiFi.."); + while (WiFi.status() != WL_CONNECTED) { + delay(1000); + Serial.print('.'); + } + + Serial.println("Connected to the WiFi network"); + + // you can also already set the item and token here, + // if they don't change throughout the program execution + // entity.id("mydevice"); + // entity.token("mydevice"); +} + +void loop() { + + // identify the item in the entity dataset + // id is used to identify the item + entity.id("mydevice"); + // token cannot be empty, can act as a password if needed + // use same string as id if password protection is not needed + entity.token("mydevice"); + + // fill in some data for the item (very similar to OOCSI) + entity.addInt("numericalTimingData", 0); + + // add the item (initially or after delete) + entity.addItem(); + + delay(10000); + + // retrieve the item + entity.getItem(); + + // extract the data (very similar to OOCSI) + int data = entity.getInt("numericalTimingData", -1); + Serial.println(data); + + delay(10000); + + // add or update data + entity.addInt("numericalTimingData", millis()); + entity.addString("stringData", "a long, long, long, long, long string - not really, but you get the point."); + + // update the item with new data + entity.updateItem(); + + delay(10000); + + // remove the item + entity.deleteItem(); + + delay(10000); +} diff --git a/dist/oocsi/examples/DataFoundry/IoT_dataset/IoT_dataset.ino b/dist/oocsi/examples/DataFoundry/IoT_dataset/IoT_dataset.ino new file mode 100644 index 0000000..9c8c306 --- /dev/null +++ b/dist/oocsi/examples/DataFoundry/IoT_dataset/IoT_dataset.ino @@ -0,0 +1,58 @@ +/********************************************************************* + Example of the ESP connecting to WiFi and accessing items in an + Entity dataset on the Data Foundry. + This works only with an existing account, project and dataset on + the Data Foundry (https://data.id.tue.nl) + *********************************************************************/ + +#include "DFDataset.h" + +// SSID of your Wifi network, the library currently does not support WPA2 Enterprise networks +const char* ssid = "yourssid"; +// Password of your Wifi network. +const char* password = "yourpassword"; + +// put the adress of Data Foundry here +const char* datafoundry = "data.id.tue.nl"; + +// create connection to dataset with server address, dataset id, and the access token +DFDataset iot(datafoundry, 2, "Gg+txzAGalvfox1BQqwlHpDFIsM2nm5U9enMOF2mA/W382zyuM3JC"); + +// put your setup code here, to run once: +void setup() { + Serial.begin(115200); + + // establish Wifi connection + WiFi.begin(ssid, password); + Serial.println("Connecting to WiFi.."); + while (WiFi.status() != WL_CONNECTED) { + delay(1000); + Serial.print('.'); + } + + Serial.println("Connected to the WiFi network"); + + // you can also already set the device and activity here, + // if they don't change throughout the program execution + // iot.device("mydevice"); + // iot.activity("idle"); +} + +void loop() { + + // specify device, can be empty + iot.device("mydevice"); + + // specify activity, can be empty + iot.activity("idle"); + + // fill in some data for the item (very similar to OOCSI) + iot.addInt("numericalTimingData", millis()); + iot.addBool("yesno", true); + iot.addString("stringData", "a long, long, long, long, long string - not really, but you get the point."); + + // log the item data to the dataset + iot.logItem(); + + delay(10000); +} \ No newline at end of file diff --git a/dist/oocsi/examples/Extras/OOCSI_wifi_multi/OOCSI_wifi_multi.ino b/dist/oocsi/examples/Extras/OOCSI_wifi_multi/OOCSI_wifi_multi.ino new file mode 100644 index 0000000..15cb6a0 --- /dev/null +++ b/dist/oocsi/examples/Extras/OOCSI_wifi_multi/OOCSI_wifi_multi.ino @@ -0,0 +1,50 @@ +/************************************************************************************* + Example of the OOCSI-ESP library connecting to a Wifi network that can be + interactively chosen using the WifiMulti functionality. + *************************************************************************************/ + +#include +#include +#include + +WiFiMulti wifiMulti; + +// name for connecting with OOCSI (hashes will be randomized) +const char* OOCSIName = "client####"; +// put the adress of your OOCSI server here, can be URL or IP address string +const char* hostserver = "your OOCSI server address"; + +// OOCSI reference for the entire sketch +OOCSI oocsi = OOCSI(); + +void setup() +{ + Serial.begin(115200); + delay(10); + + wifiMulti.addAP("ssid_from_AP_1", "your_password_for_AP_1"); + wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2"); + wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3"); + + Serial.println("Connecting any available Wifi that configured ..."); + if (wifiMulti.run() == WL_CONNECTED) { + Serial.println(""); + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + + // now connect to OOCSI without the Wifi configuration and management + oocsi.connect(OOCSIName, hostserver, processOOCSI); + + // subscribe to a channel + Serial.println("Subscribing to testchannel"); + oocsi.subscribe("testchannel"); + } +} + +void loop() { + // put your main code here, to run repeatedly: + + // let OOCSI check to process incoming data + oocsi.check(); +} diff --git a/src/DFDataset.cpp b/src/DFDataset.cpp new file mode 100644 index 0000000..4f10b87 --- /dev/null +++ b/src/DFDataset.cpp @@ -0,0 +1,357 @@ +/*************************************************************************** + * The DataFoundry library for the ESP32 and ESP 8266 to store and retrieve + * data from ESPs on the Data Foundry platform. + * + * Developed by Mathias Funk + **************************************************************************/ + +#include "DFDataset.h" + +/** + * @brief Constructor for creating a new DFDataset + * @note Should only be called once + * @retval A new DFDataset client + */ +DFDataset::DFDataset(const char* server, int id, const char* token) { + host = server; + dataset_id = id; + api_token = token; + logging = true; + jsonMessage.clear(); +} + +// iot datasets +void DFDataset::device(const char* device) { + device_id = device; +} + +void DFDataset::activity(const char* act) { + activity_id = act; +} + +// entity datasets +void DFDataset::id(const char* id) { + resource_id = id; +} + +void DFDataset::token(const char* token) { + resource_token = token; +} + +const char* root_ca_df = "-----BEGIN CERTIFICATE-----\n" \ + "MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/\n" \ + "MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\n" \ + "DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow\n" \ + "PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD\n" \ + "Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n" \ + "AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O\n" \ + "rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq\n" \ + "OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b\n" \ + "xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw\n" \ + "7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD\n" \ + "aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV\n" \ + "HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG\n" \ + "SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69\n" \ + "ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr\n" \ + "AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz\n" \ + "R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5\n" \ + "JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo\n" \ + "Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ\n" \ + "-----END CERTIFICATE-----"; + +bool DFDataset::logItem() { + + // check basic input data + if(host == NULL || api_token == NULL || dataset_id == 0) { + return false; + } + + // check message + String postMessage = String(); + serializeJson(jsonMessage, postMessage); + if(postMessage == NULL || postMessage == "null") { + return false; + } + + // set missing data + activity_id = activity_id != NULL ? activity_id : ""; + device_id = device_id != NULL ? device_id : ""; + + // compile address + snprintf_P(address, sizeof(address), PSTR("http://%s/datasets/ts/log/%i/%s"), host, dataset_id, activity_id); + + // do transmission + HTTPClient http; + http.begin(address/*, root_ca_df*/); + http.addHeader("Content-Type", "application/json"); + http.addHeader("api_token", api_token); + http.addHeader("source_id", device_id); + http.addHeader("device_id", device_id); + + int httpCode = http.POST(postMessage); + jsonMessage.clear(); + + http.end(); + + return httpCode == HTTP_CODE_OK; +} + +bool DFDataset::addItem() { + + // check basic input data + if(host == NULL || api_token == NULL || resource_id == NULL || dataset_id == 0) { + return false; + } + + // check message + String postMessage = String(); + serializeJson(jsonMessage, postMessage); + + // compile address + snprintf_P(address, sizeof(address), PSTR("http://%s/datasets/entity/%i/item/"), host, dataset_id); + + // set missing data + resource_token = resource_token != NULL ? resource_token : ""; + + // do transmission + HTTPClient http; + http.begin(address/*, root_ca_df*/); + http.addHeader("Content-Type", "application/json"); + http.addHeader("resource_id", resource_id); + http.addHeader("token", resource_token); + http.addHeader("api_token", api_token); + + int httpCode = http.POST(postMessage); + jsonMessage.clear(); + + http.end(); + + return httpCode == HTTP_CODE_OK; +} + +bool DFDataset::updateItem() { + + // check basic input data + if(host == NULL || api_token == NULL || resource_id == NULL || dataset_id == 0) { + return false; + } + + // check message + String postMessage = String(); + serializeJson(jsonMessage, postMessage); + + // compile address + snprintf_P(address, sizeof(address), PSTR("http://%s/datasets/entity/%i/item/"), host, dataset_id); + + // set missing data + resource_token = resource_token != NULL ? resource_token : ""; + + // do transmission + HTTPClient http; + http.begin(address/*, root_ca_df*/); + http.addHeader("Content-Type", "application/json"); + http.addHeader("resource_id", resource_id); + http.addHeader("token", resource_token); + http.addHeader("api_token", api_token); + + int httpCode = http.PUT(postMessage); + jsonMessage.clear(); + + http.end(); + + return httpCode == HTTP_CODE_OK; +} + +bool DFDataset::deleteItem() { + + // check basic input data + if(host == NULL || api_token == NULL || resource_id == NULL || dataset_id == 0) { + return false; + } + + // compile address + snprintf_P(address, sizeof(address), PSTR("http://%s/datasets/entity/%i/item/"), host, dataset_id); + + // set missing data + resource_token = resource_token != NULL ? resource_token : ""; + + // do transmission + HTTPClient http; + http.begin(address/*, root_ca_df*/); + http.addHeader("Content-Type", "application/json"); + http.addHeader("resource_id", resource_id); + http.addHeader("token", resource_token); + http.addHeader("api_token", api_token); + + int httpCode = http.sendRequest("DELETE"); + jsonMessage.clear(); + + String jsonResponse = http.getString(); + + http.end(); + + return httpCode == HTTP_CODE_OK; +} + +bool DFDataset::getItem() { + // check basic input data + if(host == NULL || api_token == NULL || resource_id == NULL || dataset_id == 0) { + return false; + } + + // compile address + snprintf_P(address, sizeof(address), PSTR("http://%s/datasets/entity/%i/item/"), host, dataset_id); + + // set missing data + resource_token = resource_token != NULL ? resource_token : ""; + + // do transmission + HTTPClient http; + http.begin(address/*, root_ca_df*/); + http.addHeader("Content-Type", "application/json"); + http.addHeader("resource_id", resource_id); + http.addHeader("token", resource_token); + http.addHeader("api_token", api_token); + + int httpCode = http.GET(); + jsonMessage.clear(); + + String jsonResponse = http.getString(); + + http.end(); + + if(jsonResponse.length() > 0) { + DeserializationError error = deserializeJson(jsonDocument, jsonResponse.c_str()); + if (error) { + print(F("Message parsing failed: ")); + println(error.c_str()); + return false; + } + return true; + } else { + return false; + } +} + +bool DFDataset::getBool(const char* key, bool standard) { + if(jsonDocument.isNull() || !jsonDocument.containsKey(key)) { + return standard; + } else { + return jsonDocument[key].as(); + } +} + +int DFDataset::getInt(const char* key, int standard) { + if(jsonDocument.isNull() || !jsonDocument.containsKey(key)) { + return standard; + } else { + return jsonDocument[key].as(); + } +} + +long DFDataset::getLong(const char* key, long standard) { + if(jsonDocument.isNull() || !jsonDocument.containsKey(key)) { + return standard; + } else { + return jsonDocument[key].as(); + } +} + +float DFDataset::getFloat(const char* key, float standard) { + if(jsonDocument.isNull() || !jsonDocument.containsKey(key)) { + return standard; + } else { + return jsonDocument[key].as(); + } +} + +String DFDataset::getString(const char* key, const char* standard) { + if(jsonDocument.isNull() || !jsonDocument.containsKey(key)) { + return standard; + } else { + return jsonDocument[key].as(); + } +} + +bool DFDataset::has(const char* key) { + return jsonDocument.containsKey(key); +} + +// function for outputting all (top-level) keys in the message as a comma-separated list +String DFDataset::keys() { + if(jsonDocument.isNull() || jsonDocument.size() == 0) { + return ""; + } + + // comma separated key list + String result = ""; + for (JsonPair p : jsonDocument.as()) { + if(result.length() > 0) { + result.concat(","); + } + result.concat(p.key().c_str()); + } + return result; +} + +// function for sending a bool to DFDataset +DFDataset DFDataset::addBool(const char* key, bool value) { + jsonMessage[key] = value; + return *this; +} + +// function for sending an int to DFDataset +DFDataset DFDataset::addInt(const char* key, int value) { + jsonMessage[key] = value; + return *this; +} + +// function for sending an int to DFDataset +DFDataset DFDataset::addLong(const char* key, long value) { + jsonMessage[key] = value; + return *this; +} + +// function for sending a float to DFDataset +DFDataset DFDataset::addFloat(const char* key, float value) { + jsonMessage[key] = value; + return *this; +} + +DFDataset DFDataset::addString(const char* key, const char* value) { + jsonMessage[key] = value; + return *this; +} + +void DFDataset::print(const String &message) { + if(logging) + Serial.print(message); +} + +void DFDataset::print(char message) { + if(logging) + Serial.print(message); +} + +void DFDataset::println() { + if(logging) + Serial.println(); +} + +void DFDataset::println(const String &message) { + if(logging) + Serial.println(message); +} + +void DFDataset::println(char message) { + if(logging) + Serial.println(message); +} + +void DFDataset::setActivityLEDPin(int ledPin) { + activityLEDPin = ledPin; +} + +void DFDataset::setLogging(bool log) { + logging = log; +} diff --git a/src/DFDataset.h b/src/DFDataset.h new file mode 100644 index 0000000..30b6dc3 --- /dev/null +++ b/src/DFDataset.h @@ -0,0 +1,100 @@ +/*************************************************************************** + * The DataFoundry library for the ESP32 and ESP 8266 to store and retrieve + * data from ESPs on the Data Foundry platform. + * + * Developed by Mathias Funk + **************************************************************************/ + +#ifndef DFDATASET_h +#define DFDATASET_h + +#ifdef ESP32 + #include + #include + #ifndef MSG_SIZE + #define MSG_SIZE 2048 + #endif +#else + #include + #include + #ifndef MSG_SIZE + #define MSG_SIZE 1024 + #endif +#endif +#ifndef LED_BUILTIN + #define LED_BUILTIN -1 +#endif +#include + +class DFDataset { + + public: + + // setup + DFDataset(const char* host, int id, const char* token); + + // iot datasets + void device(const char* act); + void activity(const char* act); + // entity datasets + void id(const char* act); + void token(const char* act); + + // sending data + DFDataset clear(); + DFDataset addBool(const char* key, bool value); + DFDataset addInt(const char* key, int value); + DFDataset addLong(const char* key, long value); + DFDataset addFloat(const char* key, float value); + DFDataset addString(const char* key, const char* value); + + // operations + bool logItem(); + bool addItem(); + bool updateItem(); + bool deleteItem(); + bool getItem(); + + // receiving data + bool getBool(const char* key, bool standard); + int getInt(const char* key, int standard); + long getLong(const char* key, long standard); + float getFloat(const char* key, float standard); + String getString(const char* key, const char* standard); + bool has(const char* key); + String keys(); + + // misc + void printMessage(); + void setActivityLEDPin(int ledPin); + void setLogging(bool log); + + private: + + // configuration + const char* host; + char address[200]; + const char* api_token; + const char* device_id; + const char* activity_id; + const char* resource_id; + const char* resource_token; + int dataset_id = 0; + + // data + StaticJsonDocument jsonDocument; + StaticJsonDocument jsonMessage; + String jsonMessageReceiver; + bool receivedMessage; + + // logging + int activityLEDPin; + bool logging; + void print(const String &message); + void print(char message); + void println(); + void println(const String &message); + void println(char message); +}; + +#endif