From 6682ae88c0625e80511649f10336dfc8a2085ed5 Mon Sep 17 00:00:00 2001 From: moizhusnain Date: Sun, 24 Jan 2021 06:36:45 +0500 Subject: [PATCH 01/11] Now follows new api scheme --- keywords.txt | 9 +- src/Data.cpp | 216 ++++++++++++++++++++++++++++++++++++++ src/Data.h | 43 ++++++++ src/Device.cpp | 55 +--------- src/Device.h | 14 +-- src/DuplexHandler.cpp | 106 +++++++++++++++---- src/DuplexHandler.h | 18 +++- src/EventTable.cpp | 235 ++++++++++++++++++++++++++---------------- src/EventTable.h | 57 +++++----- src/Grandeur.cpp | 9 ++ src/Grandeur.h | 8 ++ src/grandeurmacros.h | 7 +- src/grandeurtypes.cpp | 3 + src/grandeurtypes.h | 13 ++- 14 files changed, 587 insertions(+), 206 deletions(-) create mode 100644 src/Data.cpp create mode 100644 src/Data.h diff --git a/keywords.txt b/keywords.txt index bdb20fd..ee99a23 100644 --- a/keywords.txt +++ b/keywords.txt @@ -9,6 +9,7 @@ grandeur KEYWORD3 Project KEYWORD3 Datastore KEYWORD3 Device KEYWORD3 +Data KEYWORD3 ####################################### # Datatypes @@ -28,12 +29,8 @@ stringify KEYWORD2 device KEYWORD2 datastore KEYWORD2 loop KEYWORD2 -getSummary KEYWORD2 -getParms KEYWORD2 -setSummary KEYWORD2 -setParms KEYWORD2 -onSummary KEYWORD2 -onParms KEYWORD2 +get KEYWORD2 +set KEYWORD2 collection KEYWORD2 insert KEYWORD2 remove KEYWORD2 diff --git a/src/Data.cpp b/src/Data.cpp new file mode 100644 index 0000000..6fd5c0d --- /dev/null +++ b/src/Data.cpp @@ -0,0 +1,216 @@ +/** + * @file Device.h + * @date 23.01.2021 + * @author Grandeur Technologies + * + * Copyright (c) 2019 Grandeur Technologies LLP. All rights reserved. + * This file is part of the Arduino SDK for Grandeur. + * + */ + +#include "Data.h" + +// Constructors +Data::Data(String deviceID, DuplexHandler duplexHandler) { + _duplex = duplexHandler; + _deviceID = deviceID; +} + +Data::Data() {} + +void Data::get(const char* path, Callback callback) { + // Get data from server + // Create a new json object + JSONObject jsonObject; + + // Create packet + char jsonString[PACKET_SIZE]; + + // Add device id + jsonObject["deviceID"] = _deviceID; + + // Add path + jsonObject["path"] = path; + + // Conver the object to string + JSON.stringify(jsonObject).toCharArray(jsonString, PACKET_SIZE); + + // Send + _duplex.send("/device/data/get", jsonString, callback); +} + +void Data::set(const char* path, JSONObject data, Callback callback) { + // Set data to server + // Create a new json object + JSONObject jsonObject; + + // Create packet + char jsonString[PACKET_SIZE]; + + // Add device id + jsonObject["deviceID"] = _deviceID; + + // Add path + jsonObject["path"] = path; + + // Add data + jsonObject["data"] = data; + + // Conver the object to string + JSON.stringify(jsonObject).toCharArray(jsonString, PACKET_SIZE); + + // Send + _duplex.send("/device/data/set", jsonString, callback); +} + +void Data::set(const char* path, bool data, Callback callback) { + // Set data to server + // Create a new json object + JSONObject jsonObject; + + // Create packet + char jsonString[PACKET_SIZE]; + + // Add device id + jsonObject["deviceID"] = _deviceID; + + // Add path + jsonObject["path"] = path; + + // Add data + jsonObject["data"] = data; + + // Conver the object to string + JSON.stringify(jsonObject).toCharArray(jsonString, PACKET_SIZE); + + // Send + _duplex.send("/device/data/set", jsonString, callback); +} + + +void Data::set(const char* path, int data, Callback callback) { + // Set data to server + // Create a new json object + JSONObject jsonObject; + + // Create packet + char jsonString[PACKET_SIZE]; + + // Add device id + jsonObject["deviceID"] = _deviceID; + + // Add path + jsonObject["path"] = path; + + // Add data + jsonObject["data"] = data; + + // Conver the object to string + JSON.stringify(jsonObject).toCharArray(jsonString, PACKET_SIZE); + + // Send + _duplex.send("/device/data/set", jsonString, callback); +} + +void Data::set(const char* path, long data, Callback callback) { + // Set data to server + // Create a new json object + JSONObject jsonObject; + + // Create packet + char jsonString[PACKET_SIZE]; + + // Add device id + jsonObject["deviceID"] = _deviceID; + + // Add path + jsonObject["path"] = path; + + // Add data + jsonObject["data"] = data; + + // Conver the object to string + JSON.stringify(jsonObject).toCharArray(jsonString, PACKET_SIZE); + + // Send + _duplex.send("/device/data/set", jsonString, callback); +} + +void Data::set(const char* path, double data, Callback callback) { + // Set data to server + // Create a new json object + JSONObject jsonObject; + + // Create packet + char jsonString[PACKET_SIZE]; + + // Add device id + jsonObject["deviceID"] = _deviceID; + + // Add path + jsonObject["path"] = path; + + // Add data + jsonObject["data"] = data; + + // Conver the object to string + JSON.stringify(jsonObject).toCharArray(jsonString, PACKET_SIZE); + + // Send + _duplex.send("/device/data/set", jsonString, callback); +} + +void Data::set(const char* path, const char* data, Callback callback) { + // Set data to server + // Create a new json object + JSONObject jsonObject; + + // Create packet + char jsonString[PACKET_SIZE]; + + // Add device id + jsonObject["deviceID"] = _deviceID; + + // Add path + jsonObject["path"] = path; + + // Add data + jsonObject["data"] = data; + + // Conver the object to string + JSON.stringify(jsonObject).toCharArray(jsonString, PACKET_SIZE); + + // Send + _duplex.send("/device/data/set", jsonString, callback); +} + + +void Data::on(const char* path, Callback callback) { + // Place an event handler on path update + // Create a new json object + JSONObject jsonObject; + + // Create packet + char jsonString[PACKET_SIZE]; + + // Add device id + jsonObject["deviceID"] = _deviceID; + + // Add path + jsonObject["path"] = path; + + // Add data + jsonObject["event"] = "data"; + + // Conver the object to string + JSON.stringify(jsonObject).toCharArray(jsonString, PACKET_SIZE); + + // Convert path to string + std::string p(path); + + // Formulate the event + std::string event = "data/" + p; + + // Send + _duplex.subscribe(event.c_str(), jsonString, callback); +} \ No newline at end of file diff --git a/src/Data.h b/src/Data.h new file mode 100644 index 0000000..9b2dc20 --- /dev/null +++ b/src/Data.h @@ -0,0 +1,43 @@ +/** + * @file Data.h + * @date 23.01.2021 + * @author Grandeur Technologies + * + * Copyright (c) 2019 Grandeur Technologies LLP. All rights reserved. + * This file is part of the Arduino SDK for Grandeur. + * + */ + +// Including headers +#include "grandeurtypes.h" +#include "grandeurmacros.h" +#include "DuplexHandler.h" + +#ifndef DATA_H_ +#define DATA_H_ + +class Data { + // Class for handling device related functions + private: + DuplexHandler _duplex; + String _deviceID; + + public: + // Data constructor + Data(String deviceID, DuplexHandler duplexHandler); + Data(); + + // Async getter/setter methods + void get(const char* path, Callback callback); + void set(const char* path, JSONObject data, Callback callback); + void set(const char* path, bool data, Callback callback); + void set(const char* path, int data, Callback callback); + void set(const char* path, long data, Callback callback); + void set(const char* path, double data, Callback callback); + void set(const char* path, const char* data, Callback callback); + + // Sync event handlers + void on(const char* path, Callback callback); +}; + +#endif \ No newline at end of file diff --git a/src/Device.cpp b/src/Device.cpp index fbfa521..af911be 100644 --- a/src/Device.cpp +++ b/src/Device.cpp @@ -10,6 +10,7 @@ #include "Device.h" +// Constructor Device::Device(String deviceID, DuplexHandler duplexHandler) { _duplex = duplexHandler; _deviceID = deviceID; @@ -17,54 +18,8 @@ Device::Device(String deviceID, DuplexHandler duplexHandler) { Device::Device() {} -void Device::getSummary(Callback callback) { - JSONObject jsonObject; - char jsonString[PACKET_SIZE]; - jsonObject["deviceID"] = _deviceID; - JSON.stringify(jsonObject).toCharArray(jsonString, PACKET_SIZE); - _duplex.send("/device/summary/get", jsonString, callback); -} - -void Device::getParms(Callback callback) { - JSONObject jsonObject; - char jsonString[PACKET_SIZE]; - jsonObject["deviceID"] = _deviceID; - JSON.stringify(jsonObject).toCharArray(jsonString, PACKET_SIZE); - _duplex.send("/device/parms/get", jsonString, callback); -} - -void Device::setSummary(JSONObject summary, Callback callback) { - JSONObject jsonObject; - char jsonString[PACKET_SIZE]; - jsonObject["deviceID"] = _deviceID; - jsonObject["summary"] = summary; - JSON.stringify(jsonObject).toCharArray(jsonString, PACKET_SIZE); - _duplex.send("/device/summary/set", jsonString, callback); -} - -void Device::setParms(JSONObject parms, Callback callback) { - JSONObject jsonObject; - char jsonString[PACKET_SIZE]; - jsonObject["deviceID"] = _deviceID; - jsonObject["parms"] = parms; - JSON.stringify(jsonObject).toCharArray(jsonString, PACKET_SIZE); - _duplex.send("/device/parms/set", jsonString, callback); -} - -void Device::onSummary(Callback updateHandler) { - JSONObject jsonObject; - char jsonString[PACKET_SIZE]; - jsonObject["deviceID"] = _deviceID; - jsonObject["event"] = "deviceSummary"; - JSON.stringify(jsonObject).toCharArray(jsonString, PACKET_SIZE); - _duplex.subscribe(SUMMARYUPDATE, jsonString, updateHandler); -} - -void Device::onParms(Callback updateHandler) { - JSONObject jsonObject; - char jsonString[PACKET_SIZE]; - jsonObject["deviceID"] = _deviceID; - jsonObject["event"] = "deviceParms"; - JSON.stringify(jsonObject).toCharArray(jsonString, PACKET_SIZE); - _duplex.subscribe(PARMSUPDATE, jsonString, updateHandler); +// Return reference to data +Data Device::data() { + // Return new device class object + return Data(_deviceID, _duplex); } \ No newline at end of file diff --git a/src/Device.h b/src/Device.h index e64fd26..58c3e90 100644 --- a/src/Device.h +++ b/src/Device.h @@ -12,6 +12,7 @@ #include "grandeurtypes.h" #include "grandeurmacros.h" #include "DuplexHandler.h" +#include "Data.h" #ifndef DEVICE_H_ #define DEVICE_H_ @@ -19,22 +20,17 @@ class Device { // Class for handling device related functions private: + // Store duplex and device id DuplexHandler _duplex; String _deviceID; + public: // Device constructor Device(String deviceID, DuplexHandler duplexHandler); Device(); - // Async getter/setter methods - void getSummary(Callback callback); - void getParms(Callback callback); - void setSummary(JSONObject summary, Callback callback); - void setParms(JSONObject parms, Callback callback); - - // Listeners for events from Grandeur - void onSummary(Callback callback); - void onParms(Callback callback); + // Instantiator methods - return the objects of their classes + Data data(); }; #endif \ No newline at end of file diff --git a/src/DuplexHandler.cpp b/src/DuplexHandler.cpp index a2a904b..b70b192 100644 --- a/src/DuplexHandler.cpp +++ b/src/DuplexHandler.cpp @@ -11,27 +11,37 @@ #include "DuplexHandler.h" #include "arduinoWebSockets/WebSockets.h" -/* VARIABLE INITIALIZATIONS */ +/* Create client */ WebSocketsClient client; + +// Init ping counter unsigned long millisCounterForPing = 0; -const char* subscriptionTopics[] = {"deviceSummary", "deviceParms"}; + +// Define queue size size_t sendQueueSize = 0; + +// Create an array equal to max send queue size SendData* sendQueue[SENDQUEUE_SIZE] = {}; + +// Init status handler and variable short DuplexHandler::_status = DISCONNECTED; void (*DuplexHandler::_connectionCallback)(bool) = [](bool connectionEventHandler) {}; +// Create a new event table and subscriptions EventTable DuplexHandler::_eventsTable; -Callback DuplexHandler::_subscriptions[4] = {}; +EventTable DuplexHandler::_subscriptions; -/* EVENT HANDLER FUNCTIONS */ +/* Deifne event handler */ void duplexEventHandler(WStype_t eventType, uint8_t* packet, size_t length); DuplexHandler::DuplexHandler(Config config) { + // Constructor _query = "/?type=device&apiKey=" + config.apiKey; _token = config.token; } DuplexHandler::DuplexHandler() { + // Overload the contructor _query = "/?type=device"; _token = ""; } @@ -39,24 +49,31 @@ DuplexHandler::DuplexHandler() { void DuplexHandler::init(void) { // Setting up event handler client.onEvent(&duplexEventHandler); + // Scheduling reconnect every 5 seconds if it disconnects client.setReconnectInterval(5000); + // Opening up the connection client.beginSSL(GRANDEUR_URL, GRANDEUR_PORT, _query, GRANDEUR_FINGERPRINT, "node"); + + // Set auth header char tokenArray[_token.length() + 1]; _token.toCharArray(tokenArray, _token.length() + 1); client.setAuthorization(tokenArray); } void DuplexHandler::onConnectionEvent(void connectionEventHandler(bool)) { + // Event handler for connection _connectionCallback = connectionEventHandler; } short DuplexHandler::getStatus() { + // Return status return _status; } void DuplexHandler::loop(bool valve) { + // Give duplex time to execute if(valve) { // If valve is true => valve is open if(millis() - millisCounterForPing >= PING_INTERVAL) { @@ -64,42 +81,67 @@ void DuplexHandler::loop(bool valve) { millisCounterForPing = millis(); ping(); } + // Running duplex loop client.loop(); } } void DuplexHandler::send(const char* task, const char* payload, Callback callback) { + // Check connection status if(_status != CONNECTED) { + // Add to queue if not connected sendQueue[sendQueueSize++] = new SendData(task, payload, callback); return ; } + + // Create packet char packet[PACKET_SIZE]; + + // Generate packet id GrandeurID packetID = millis(); + // Saving callback to eventsTable _eventsTable.insert(task, packetID, callback); + _eventsTable.print(); + _subscriptions.print(); + // Formatting the packet snprintf(packet, PACKET_SIZE, "{\"header\": {\"id\": %lu, \"task\": \"%s\"}, \"payload\": %s}", packetID, task, payload); + // Sending to server client.sendTXT(packet); } -void DuplexHandler::subscribe(short event, const char* payload, Callback updateHandler) { - // Saving updateHandler callback to subscriptions Array - _subscriptions[event] = updateHandler; +void DuplexHandler::subscribe(const char* event, const char* payload, Callback updateHandler) { + // Generate an id + GrandeurID eventID = millis(); + + // Saving callback to eventsTable + _subscriptions.insert(event, eventID, updateHandler); + _eventsTable.print(); + _subscriptions.print(); + + // Saving callback in event table with key send("/topic/subscribe", payload, [](JSONObject payload) {}); } -/** This function pings the cloud to keep the connection alive. -*/ + void DuplexHandler::ping() { + // Ping handler if(_status == CONNECTED) { + // Generate packet char packet[PING_PACKET_SIZE]; + + // Create id GrandeurID packetID = millis(); + // Saving callback to eventsTable _eventsTable.insert("ping", packetID, [](JSONObject feed) {}); + // Formatting the packet snprintf(packet, PING_PACKET_SIZE, "{\"header\": {\"id\": %lu, \"task\": \"ping\"}}", packetID); + // Sending to server client.sendTXT(packet); } @@ -111,14 +153,19 @@ void DuplexHandler::ping() { * @param length: The size of the @param packet. */ void duplexEventHandler(WStype_t eventType, uint8_t* packet, size_t length) { - JSONObject updateObject; + + // Switch over event type switch(eventType) { case WStype_CONNECTED: // When duplex connection opens DuplexHandler::_status = CONNECTED; + + // Generate callback DuplexHandler::_connectionCallback(DuplexHandler::_status); + // Resetting ping millis counter millisCounterForPing = millis(); + // Sending all queued messages for(int i = 0; i < sendQueueSize; i++) { DuplexHandler::send(sendQueue[i]->task, sendQueue[i]->payload, sendQueue[i]->callback); @@ -128,36 +175,57 @@ void duplexEventHandler(WStype_t eventType, uint8_t* packet, size_t length) { case WStype_DISCONNECTED: // When duplex connection closes DuplexHandler::_status = DISCONNECTED; + + // Clear event table + DuplexHandler::_eventsTable.clear(); + + // Generate connection event return DuplexHandler::_connectionCallback(DuplexHandler::_status); case WStype_TEXT: + Serial.printf("%s\n", packet); + // When a duplex message is received. JSONObject messageObject = JSON.parse((char*) packet); + + // Handle parsing errors if (JSON.typeof(messageObject) == "undefined") { // Just for internal errors of Arduino_JSON // if the parsing fails. DEBUG_GRANDEUR("Parsing input failed!"); return; } + + // If it is an update instead of response to a task if(messageObject["header"]["task"] == "update") { - for(int i = 0; i < NUMBER_OF_TOPICS; i++) { - if(messageObject["payload"]["event"] == subscriptionTopics[i]) { - DuplexHandler::_subscriptions[i](messageObject["payload"]["update"]); - return ; - } - } + // Formulate the key + std::string event((const char*) messageObject["payload"]["event"]); + std::string path((const char*) messageObject["payload"]["path"]); + + // Emit the event + DuplexHandler::_subscriptions.emit(event + "/" + path, messageObject["payload"]); + + // Return + return; } + // Just return if it is unpair event else if(messageObject["header"]["task"] == "unpair") { return ; } + // Fetching event callback function from the events Table Callback callback = DuplexHandler::_eventsTable.findAndRemove( (const char*) messageObject["header"]["task"], (GrandeurID) messageObject["header"]["id"] ); - if(!callback) { - return; - } + + DuplexHandler::_eventsTable.print(); + DuplexHandler::_subscriptions.print(); + + // If not found then simply return + if(!callback) return; + + // Or otherwise resolve the event return callback(messageObject["payload"]); } } diff --git a/src/DuplexHandler.h b/src/DuplexHandler.h index 7f14bc0..88c29a1 100644 --- a/src/DuplexHandler.h +++ b/src/DuplexHandler.h @@ -21,28 +21,39 @@ class DuplexHandler { private: // Connection query String _query; + // Connection token String _token; + // Connection state variable static short _status; + // Events Table static EventTable _eventsTable; - // Subscription Array for update handler functions - static Callback _subscriptions[4]; + + // Subscriptions + static EventTable _subscriptions; // Container for connection callback static void (*_connectionCallback)(bool); public: + // Constructor DuplexHandler(Config config); DuplexHandler(); + + // Init the connection void init(void); + // Ping function to keep connection alive. void ping(); + // Function to send a generic duplex message. static void send(const char* task, const char* payload, Callback callback); + // Function to subscribe to a device topic. - void subscribe(short event, const char* payload, Callback updateHandler); + void subscribe(const char* event, const char* payload, Callback updateHandler); + // Function to schedule an event handler for connection with Grandeur void onConnectionEvent(void connectionEventHandler(bool)); @@ -53,7 +64,6 @@ class DuplexHandler { void loop(bool valve); friend void duplexEventHandler(WStype_t eventType, uint8_t* packet, size_t length); - }; #endif \ No newline at end of file diff --git a/src/EventTable.cpp b/src/EventTable.cpp index d592bbe..6db1265 100644 --- a/src/EventTable.cpp +++ b/src/EventTable.cpp @@ -8,167 +8,230 @@ * */ +// Inlcude event table #include #include +#include -const char* routes[T_S] = - {"ping", "/topic/subscribe", "/topic/unsubscribe", "/topics/unsubscribe", - "/device/summary/get", "/device/parms/get", "/device/summary/set", "/device/parms/set", - "/datastore/insert", "/datastore/delete", "/datastore/update", "/datastore/pipeline"}; - -EventTableEntry::EventTableEntry(EventTableKey k, EventTableData v) { - this->k= k; - this->v = v; +// Implement event table block +EventTableEntry::EventTableEntry(EventKey key, EventID id, EventData data) { + this->key = key; + this->id = id; + this->data = data; this->next = NULL; } +// Implement event table constructor EventTable::EventTable() { - t = new EventTableEntry * [T_S]; - for (int i = 0; i < T_S; i++) { - t[i] = NULL; - } + // Init table as null + table = NULL; } -int EventTable::hashFunc(EventTableKey k) { - for(int i = 0; i < T_S; i++) { - if(routes[i] == k) { - return i; - } - } - return (T_S - 1); -} +int EventTable::insert(EventKey key, EventID id, EventData data) { -int EventTable::insert(EventTableKey k, EventID id, EventData data) { - int h = hashFunc(k); - if(t[h] == NULL) { - // If this bucket is empty, + // If bucket is empty, + if(table == NULL) { // creating the first entry - t[h] = new EventTableEntry(k, {id, data}); + table = new EventTableEntry(key, id, data); return 0; } - if(t[h]->v.id == id) { + + // Otherwise resolve the base case where the starting block id + // is duplicate of the new supllied + if(table->id == id) { // If entry is found in the first element, // replacing its data - t[h]->v.data = data; + table->data = data; return 0; } + // If the bucket is not empty, // getting ready for traversing the chain - EventTableEntry* p = t[h]; - while (p->next != NULL && p->next->v.id != id) { + EventTableEntry * p = table; + + // Move to next block while we aren't at the end + while (p->next != NULL) { + // or we haven't found a duplicate in next block + if (p->next->id == id) break; + + // Keep moving p = p->next; } + + // When found a duplicate if (p->next != NULL) { - // If found an index without reaching the end of chain, + // Without reaching the end of chain, // just replace the data - p->next->v.data = data; + p->next->data = data; return 0; } + // If the end of chain is reached, // creating a new entry in the chain - p->next = new EventTableEntry(k, {id, data}); + p->next = new EventTableEntry(key, id, data); return 0; } -int EventTable::remove(EventTableKey k, EventID id) { - int h = hashFunc(k); - if(t[h] == NULL) { - // If this bucket is empty, +int EventTable::remove(EventKey key, EventID id) { + // Check if bucket is empty + if(table == NULL) { // which means the entry does not exist return -1; } - if(t[h]->v.id == id) { - // If entry is found in the first element, - // deleting it and pulling the chain backwards - EventTableEntry* p = t[h]; - t[h] = t[h]->next; + + // If the id was found in first block + if(table->id == id) { + // Pull the chain backwards + EventTableEntry* p = table; + table = table->next; + + // and delete it delete p; return 0; } + // If the bucket is not empty, // getting ready for traversing the chain - EventTableEntry* p = t[h]; + EventTableEntry* p = table; + + // While not the end has reached while (p->next != NULL) { - if (p->next->v.id == id) - // If element is found, - // breaking out of the loop - break; + // Break if the next block has the id we need + if (p->next->id == id) break; + + // Keep moving p = p->next; } + + // Handle case where we reached the end if (p->next == NULL) { - // If the end of the chain is reached, - // and no element is found + // No element is found return -1; } + // If the element is found + // Then pull the chain backward EventTableEntry* q = p->next; p->next = p->next->next; + + // and delete it delete q; return 0; } -EventData EventTable::findAndRemove(EventTableKey k, EventID id) { - int h = hashFunc(k); - if(t[h] == NULL) { - // If this bucket is empty, +EventData EventTable::findAndRemove(EventKey key, EventID id) { + // Check if bucket is empty + if(table == NULL) { // which means the entry does not exist return NULL; } - if(t[h]->v.id == id) { - // If entry is found in the first element, - // copying it, deleting it and pulling the chain backwards - EventTableEntry* p = t[h]; - EventData data = p->v.data; - t[h] = t[h]->next; + + // If the id was found in first block + if(table->id == id) { + // Pull the chain backwards + EventTableEntry* p = table; + EventData data = p->data; + table = table->next; + + // and delete it delete p; return data; } + // If the bucket is not empty, // getting ready for traversing the chain - EventTableEntry* p = t[h]; + EventTableEntry* p = table; + + // While not the end has reached while (p->next != NULL) { - if (p->next->v.id == id) - // If element is found, - // breaking out of the loop - break; + // Break if the next block has the id we need + if (p->next->id == id) break; + + // Keep moving p = p->next; } + + // Handle case where we reached the end if (p->next == NULL) { - // If the end of the chain is reached, - // and no element is found + // No element is found return NULL; } + // If the element is found - // copying its data, deleting it and pulling the chain backwards + // Then pull the chain backward EventTableEntry* q = p->next; - EventData data = q->v.data; + EventData data = p->data; p->next = p->next->next; + + // and delete it delete q; return data; } -/* ONLY FOR PRINTABLE DATA TYPES */ -void EventTable::print() { - for(int i = 0; i < T_S; i++) { - EventTableEntry* p = t[i]; - std::cout< "; - while (p != NULL) { - std::cout<k<<" : "; - std::cout<v.id<< " : "; - //std::cout<v.data<<" -> "; - p = p->next; +int EventTable::emit(EventKey key, JSONObject packet) { + // Created a regex + std::regex pattern("(" + key + ")(.*)"); + + // If the bucket is not empty, + // getting ready for traversing the chain + EventTableEntry* p = table; + + // While not the end has reached + while (p != NULL) { + // We will use regex to match the key of the block + if (std::regex_match(p->key, pattern)) { + // Then emit packet to callback + p->data(packet); } - std::cout<<"\n"; + + // Keep moving + p = p->next; } + + return 0; } -EventTable::~EventTable() { - for (int i = 0; i < T_S; i++) { - if (t[i] != NULL) - for(EventTableEntry* p = t[i]; p != NULL; p = p->next) { - delete p; - t[i] = NULL; - } +void EventTable::print() { + // Loop over the event table + EventTableEntry* p = table; + + // Print header + Serial.printf("\n*******Table*******\n"); + + // While not the end + while (p != NULL) { + // Print the id + Serial.printf("%s %d\n", p->key.c_str(), p->id); + + p = p->next; } - delete[] t; + + // Print footer + Serial.printf("*******************\n"); +} + +void EventTable::clear() { + // Function to delete all blocks + // If the bucket is not empty, + // getting ready for traversing the chain + EventTableEntry* p = table; + + // While not the end has reached + while (p != NULL) { + // Copy block address to a pointer + EventTableEntry* next = p->next; + + // delete p + delete p; + + // Move next + p = next; + } + + // Mark table as empty + table = NULL; +} + +EventTable::~EventTable() { + clear(); } \ No newline at end of file diff --git a/src/EventTable.h b/src/EventTable.h index 4ddd058..5b5b19d 100644 --- a/src/EventTable.h +++ b/src/EventTable.h @@ -15,49 +15,56 @@ #ifndef EVENTTABLE_H_ #define EVENTTABLE_H_ -/*TYPEDEFS*/ // EventID typedef GrandeurID EventID; + //EventData typedef Callback EventData; -// Event table data -typedef struct { - EventID id; - EventData data; -} EventTableData; -// Event table key -typedef std::string EventTableKey; - -// Event table size -const int T_S = 16; -// Routes Array -extern const char* routes[T_S]; +// Event key +typedef std::string EventKey; -// Event table entry +// Event table entry is the block which represents +// an event class EventTableEntry { public: - EventTableKey k; - EventTableData v; + EventKey key; + EventID id; + EventData data; EventTableEntry* next; - EventTableEntry(EventTableKey k, EventTableData v); + + // Constructor + EventTableEntry(EventKey key, EventID id, EventData data); }; +// The main class class EventTable { private: - EventTableEntry **t; + // Define table + EventTableEntry *table; + public: - // Constructor for a hashtable + // Constructor for a table EventTable(); - // Hash function for Event Table - int hashFunc(EventTableKey k); + // Method to insert an entry into the hashtable - int insert(EventTableKey k, EventID id, EventData data); - // Method to remove an entry from the hashtable - int remove(EventTableKey k, EventID id); + int insert(EventKey key, EventID id, EventData data); + + // Method to remove an entry from the table + int remove(EventKey key, EventID id); + // Method to find and remove an entry from the hashtable - EventData findAndRemove(EventTableKey k, EventID id); + EventData findAndRemove(EventKey key, EventID id); + + // Method to send some data to all callbacks at a key + int emit(EventKey key, JSONObject packet); + + // Print table entreis void print(); + + // Clear event table entries + void clear(); + // Destructor for a hashtable ~EventTable(); }; diff --git a/src/Grandeur.cpp b/src/Grandeur.cpp index 1cc2068..accd097 100644 --- a/src/Grandeur.cpp +++ b/src/Grandeur.cpp @@ -18,30 +18,39 @@ Grandeur::Grandeur() {} Project Grandeur::init(String apiKey, String token) { // Setting config _config = {apiKey, token}; + // Creating a new project reference. Project project; + // Duplex handles the realtime connection with the project. project._duplexHandler = DuplexHandler(_config); + // Starting Duplex. project._duplexHandler.init(); + + // Return project object return project; } Project::Project() {} void Project::onConnection(void connectionCallback(bool)) { + // Connection handler for duplex _duplexHandler.onConnectionEvent(connectionCallback); } bool Project::isConnected(void) { + // Return status of duplex return _duplexHandler.getStatus() == CONNECTED; } Device Project::device(String deviceID) { + // Return new device class object return Device(deviceID, _duplexHandler); } Datastore Project::datastore(void) { + // Return new datastore class object return Datastore(_duplexHandler); } diff --git a/src/Grandeur.h b/src/Grandeur.h index 058f935..735cd4c 100644 --- a/src/Grandeur.h +++ b/src/Grandeur.h @@ -22,12 +22,15 @@ class Project { // Class for handling a complete project private: DuplexHandler _duplexHandler; + public: // Project constructor Project(); + // Connection related methods void onConnection(void connectionCallback(bool)); bool isConnected(void); + // Instantiator methods - return the objects of their classes Device device(String deviceID); Datastore datastore(void); @@ -40,9 +43,14 @@ class Project { class Grandeur { private: + // Create new config object Config _config; + public: + // Constructor of Grandeur Grandeur(); + + // Function to init the connection Project init(String apiKey, String token); }; diff --git a/src/grandeurmacros.h b/src/grandeurmacros.h index bb2a11a..a435697 100644 --- a/src/grandeurmacros.h +++ b/src/grandeurmacros.h @@ -9,7 +9,7 @@ */ // Connection macros -#define GRANDEUR_URL "api.grandeur.tech" +#define GRANDEUR_URL "trex.dev.api.grandeur.tech" #define GRANDEUR_PORT 443 #define GRANDEUR_FINGERPRINT "" @@ -41,8 +41,3 @@ // Macros for connection status #define DISCONNECTED false #define CONNECTED true - -// Indexes for update handler callbacks in subscriptions array -#define NUMBER_OF_TOPICS 2 -#define SUMMARYUPDATE 0 -#define PARMSUPDATE 1 diff --git a/src/grandeurtypes.cpp b/src/grandeurtypes.cpp index e520057..585c92b 100644 --- a/src/grandeurtypes.cpp +++ b/src/grandeurtypes.cpp @@ -11,16 +11,19 @@ #include #include "Arduino.h" +// Define config class Config::Config(String apiKey, String token) { this->apiKey = apiKey; this->token = token; } +// Config override constructor Config::Config() { this->apiKey = ""; this->token = ""; } +// Object which stores the task while it is on queue SendData::SendData(const char* task, const char* payload, Callback callback) { strcpy(this->task, task); strcpy(this->payload, payload); diff --git a/src/grandeurtypes.h b/src/grandeurtypes.h index 27fc39b..3ef36eb 100644 --- a/src/grandeurtypes.h +++ b/src/grandeurtypes.h @@ -15,16 +15,25 @@ #ifndef GRANDEURTYPES_H_ #define GRANDEURTYPES_H_ +// Include json typedef JSONVar JSONObject; + +// Define callback typedef void (*Callback)(JSONObject); + +// Define send function typedef void (*Send)(const char* task, const char* payload, Callback callback); + +// Define Grandeur ID typedef long GrandeurID; -// Config class for grandeur configurations +// Config class for storing configurations of connection class Config { public: String apiKey; String token; + + // Constructor Config(String apiKey, String token); Config(); }; @@ -35,6 +44,8 @@ class SendData { char task[TASK_SIZE]; char payload[PACKET_SIZE]; Callback callback; + + // Constructor SendData( const char* task, const char* payload, From fb9f7c50c9a22ace9d5c8f898708688d6dee433e Mon Sep 17 00:00:00 2001 From: moizhusnain Date: Mon, 25 Jan 2021 07:27:38 +0500 Subject: [PATCH 02/11] Implemented callback with template --- src/Data.cpp | 16 ++++++++-------- src/Data.h | 16 ++++++++-------- src/Datastore.cpp | 10 +++++----- src/Datastore.h | 10 +++++----- src/DuplexHandler.cpp | 10 +++++----- src/DuplexHandler.h | 4 ++-- src/EventTable.h | 2 +- src/grandeurtypes.cpp | 2 +- src/grandeurtypes.h | 43 ++++++++++++++++++++++++++++++++++++++----- 9 files changed, 73 insertions(+), 40 deletions(-) diff --git a/src/Data.cpp b/src/Data.cpp index 6fd5c0d..0c99e57 100644 --- a/src/Data.cpp +++ b/src/Data.cpp @@ -18,7 +18,7 @@ Data::Data(String deviceID, DuplexHandler duplexHandler) { Data::Data() {} -void Data::get(const char* path, Callback callback) { +void Data::get(const char* path, Callback callback) { // Get data from server // Create a new json object JSONObject jsonObject; @@ -39,7 +39,7 @@ void Data::get(const char* path, Callback callback) { _duplex.send("/device/data/get", jsonString, callback); } -void Data::set(const char* path, JSONObject data, Callback callback) { +void Data::set(const char* path, JSONObject data, Callback callback) { // Set data to server // Create a new json object JSONObject jsonObject; @@ -63,7 +63,7 @@ void Data::set(const char* path, JSONObject data, Callback callback) { _duplex.send("/device/data/set", jsonString, callback); } -void Data::set(const char* path, bool data, Callback callback) { +void Data::set(const char* path, bool data, Callback callback) { // Set data to server // Create a new json object JSONObject jsonObject; @@ -88,7 +88,7 @@ void Data::set(const char* path, bool data, Callback callback) { } -void Data::set(const char* path, int data, Callback callback) { +void Data::set(const char* path, int data, Callback callback) { // Set data to server // Create a new json object JSONObject jsonObject; @@ -112,7 +112,7 @@ void Data::set(const char* path, int data, Callback callback) { _duplex.send("/device/data/set", jsonString, callback); } -void Data::set(const char* path, long data, Callback callback) { +void Data::set(const char* path, long data, Callback callback) { // Set data to server // Create a new json object JSONObject jsonObject; @@ -136,7 +136,7 @@ void Data::set(const char* path, long data, Callback callback) { _duplex.send("/device/data/set", jsonString, callback); } -void Data::set(const char* path, double data, Callback callback) { +void Data::set(const char* path, double data, Callback callback) { // Set data to server // Create a new json object JSONObject jsonObject; @@ -160,7 +160,7 @@ void Data::set(const char* path, double data, Callback callback) { _duplex.send("/device/data/set", jsonString, callback); } -void Data::set(const char* path, const char* data, Callback callback) { +void Data::set(const char* path, const char* data, Callback callback) { // Set data to server // Create a new json object JSONObject jsonObject; @@ -185,7 +185,7 @@ void Data::set(const char* path, const char* data, Callback callback) { } -void Data::on(const char* path, Callback callback) { +void Data::on(const char* path, Callback callback) { // Place an event handler on path update // Create a new json object JSONObject jsonObject; diff --git a/src/Data.h b/src/Data.h index 9b2dc20..b06f5fc 100644 --- a/src/Data.h +++ b/src/Data.h @@ -28,16 +28,16 @@ class Data { Data(); // Async getter/setter methods - void get(const char* path, Callback callback); - void set(const char* path, JSONObject data, Callback callback); - void set(const char* path, bool data, Callback callback); - void set(const char* path, int data, Callback callback); - void set(const char* path, long data, Callback callback); - void set(const char* path, double data, Callback callback); - void set(const char* path, const char* data, Callback callback); + void get(const char* path, Callback callback); + void set(const char* path, JSONObject data, Callback callback); + void set(const char* path, bool data, Callback callback); + void set(const char* path, int data, Callback callback); + void set(const char* path, long data, Callback callback); + void set(const char* path, double data, Callback callback); + void set(const char* path, const char* data, Callback callback); // Sync event handlers - void on(const char* path, Callback callback); + void on(const char* path, Callback callback); }; #endif \ No newline at end of file diff --git a/src/Datastore.cpp b/src/Datastore.cpp index f5b98cb..9f7a4c3 100644 --- a/src/Datastore.cpp +++ b/src/Datastore.cpp @@ -26,7 +26,7 @@ Collection::Collection(String name, DuplexHandler duplexHandler) { _duplex = duplexHandler; } -void Collection::insert(JSONObject documents, Callback inserted) { +void Collection::insert(JSONObject documents, Callback inserted) { JSONObject jsonObject; char jsonString[PACKET_SIZE]; @@ -38,7 +38,7 @@ void Collection::insert(JSONObject documents, Callback inserted) { _duplex.send("/datastore/insert", jsonString, inserted); } -void Collection::remove(JSONObject filter, Callback removed) { +void Collection::remove(JSONObject filter, Callback removed) { JSONObject jsonObject; char jsonString[PACKET_SIZE]; @@ -50,7 +50,7 @@ void Collection::remove(JSONObject filter, Callback removed) { _duplex.send("/datastore/delete", jsonString, removed); } -void Collection::update(JSONObject filter, JSONObject update, Callback updated) { +void Collection::update(JSONObject filter, JSONObject update, Callback updated) { JSONObject jsonObject; char jsonString[PACKET_SIZE]; @@ -63,7 +63,7 @@ void Collection::update(JSONObject filter, JSONObject update, Callback updated) _duplex.send("/datastore/update", jsonString, updated); } -void Collection::search(JSONObject filter, JSONObject projection, int pageNumber, Callback searched) { +void Collection::search(JSONObject filter, JSONObject projection, int pageNumber, Callback searched) { Pipeline searchPipeline = Pipeline(_name, {}, _duplex).match(filter); if(projection == undefined) {} else { @@ -116,7 +116,7 @@ Pipeline Pipeline::sort(JSONObject specs) { return Pipeline(_collection, _query, _duplex); } -void Pipeline::execute(int pageNumber, Callback executed) { +void Pipeline::execute(int pageNumber, Callback executed) { JSONObject jsonObject; char jsonString[PACKET_SIZE]; diff --git a/src/Datastore.h b/src/Datastore.h index a6a42ee..5ec3565 100644 --- a/src/Datastore.h +++ b/src/Datastore.h @@ -28,7 +28,7 @@ class Pipeline { Pipeline project(JSONObject specs); Pipeline group(JSONObject condition, JSONObject fields); Pipeline sort(JSONObject specs); - void execute(int pageNumber, Callback executed); + void execute(int pageNumber, Callback executed); }; class Collection { @@ -40,10 +40,10 @@ class Collection { // Collection constructor Collection(String name, DuplexHandler duplexHandler); // Methods - void insert(JSONObject documents, Callback inserted); - void remove(JSONObject filter, Callback removed); - void update(JSONObject filter, JSONObject update, Callback updated); - void search(JSONObject filter, JSONObject projection, int pageNumber, Callback searched); + void insert(JSONObject documents, Callback inserted); + void remove(JSONObject filter, Callback removed); + void update(JSONObject filter, JSONObject update, Callback updated); + void search(JSONObject filter, JSONObject projection, int pageNumber, Callback searched); Pipeline pipeline(void); }; diff --git a/src/DuplexHandler.cpp b/src/DuplexHandler.cpp index b70b192..8c4929d 100644 --- a/src/DuplexHandler.cpp +++ b/src/DuplexHandler.cpp @@ -87,7 +87,7 @@ void DuplexHandler::loop(bool valve) { } } -void DuplexHandler::send(const char* task, const char* payload, Callback callback) { +void DuplexHandler::send(const char* task, const char* payload, Callback callback) { // Check connection status if(_status != CONNECTED) { // Add to queue if not connected @@ -113,7 +113,7 @@ void DuplexHandler::send(const char* task, const char* payload, Callback callbac client.sendTXT(packet); } -void DuplexHandler::subscribe(const char* event, const char* payload, Callback updateHandler) { +void DuplexHandler::subscribe(const char* event, const char* payload, Callback updateHandler) { // Generate an id GrandeurID eventID = millis(); @@ -123,7 +123,7 @@ void DuplexHandler::subscribe(const char* event, const char* payload, Callback u _subscriptions.print(); // Saving callback in event table with key - send("/topic/subscribe", payload, [](JSONObject payload) {}); + send("/topic/subscribe", payload, NULL); } @@ -137,7 +137,7 @@ void DuplexHandler::ping() { GrandeurID packetID = millis(); // Saving callback to eventsTable - _eventsTable.insert("ping", packetID, [](JSONObject feed) {}); + _eventsTable.insert("ping", packetID, NULL); // Formatting the packet snprintf(packet, PING_PACKET_SIZE, "{\"header\": {\"id\": %lu, \"task\": \"ping\"}}", packetID); @@ -214,7 +214,7 @@ void duplexEventHandler(WStype_t eventType, uint8_t* packet, size_t length) { } // Fetching event callback function from the events Table - Callback callback = DuplexHandler::_eventsTable.findAndRemove( + Callback callback = DuplexHandler::_eventsTable.findAndRemove( (const char*) messageObject["header"]["task"], (GrandeurID) messageObject["header"]["id"] ); diff --git a/src/DuplexHandler.h b/src/DuplexHandler.h index 88c29a1..984b26c 100644 --- a/src/DuplexHandler.h +++ b/src/DuplexHandler.h @@ -49,10 +49,10 @@ class DuplexHandler { void ping(); // Function to send a generic duplex message. - static void send(const char* task, const char* payload, Callback callback); + static void send(const char* task, const char* payload, Callback callback); // Function to subscribe to a device topic. - void subscribe(const char* event, const char* payload, Callback updateHandler); + void subscribe(const char* event, const char* payload, Callback updateHandler); // Function to schedule an event handler for connection with Grandeur void onConnectionEvent(void connectionEventHandler(bool)); diff --git a/src/EventTable.h b/src/EventTable.h index 5b5b19d..fecbada 100644 --- a/src/EventTable.h +++ b/src/EventTable.h @@ -19,7 +19,7 @@ typedef GrandeurID EventID; //EventData -typedef Callback EventData; +typedef Callback EventData; // Event key typedef std::string EventKey; diff --git a/src/grandeurtypes.cpp b/src/grandeurtypes.cpp index 585c92b..59c98d9 100644 --- a/src/grandeurtypes.cpp +++ b/src/grandeurtypes.cpp @@ -24,7 +24,7 @@ Config::Config() { } // Object which stores the task while it is on queue -SendData::SendData(const char* task, const char* payload, Callback callback) { +SendData::SendData(const char* task, const char* payload, Callback callback) { strcpy(this->task, task); strcpy(this->payload, payload); this->callback = callback; diff --git a/src/grandeurtypes.h b/src/grandeurtypes.h index 3ef36eb..0151e51 100644 --- a/src/grandeurtypes.h +++ b/src/grandeurtypes.h @@ -18,11 +18,44 @@ // Include json typedef JSONVar JSONObject; -// Define callback -typedef void (*Callback)(JSONObject); +// Define Callback using template +template +class Callback { + private: + // Create a private variable + void (*_c)(T); + + public: + // Default constructor will init the pointer + Callback() { + // We will init the context + _c = NULL; + } + + // It will receive an function + Callback(void (*c)(T)) { + // We will store it in context + _c = c; + } + + // Then we will override the function call + // operator to pass data to callback that we stored + // in the context + void operator()(T data) { + // Call the function stored in context + _c(data); + } + + // Override bool operator not + bool operator!() { + // Return true if callback was set + if (!_c) return true; + else return false; + } +}; // Define send function -typedef void (*Send)(const char* task, const char* payload, Callback callback); +typedef void (*Send)(const char* task, const char* payload, Callback callback); // Define Grandeur ID typedef long GrandeurID; @@ -43,13 +76,13 @@ class SendData { public: char task[TASK_SIZE]; char payload[PACKET_SIZE]; - Callback callback; + Callback callback; // Constructor SendData( const char* task, const char* payload, - Callback callback + Callback callback ); }; From d5d57e1e2d972cb5eb15c4b511e7cf999d8afca8 Mon Sep 17 00:00:00 2001 From: moizhusnain Date: Tue, 26 Jan 2021 01:10:55 +0500 Subject: [PATCH 03/11] New callback implmentation The event handlers of data can be now type specific --- src/Data.cpp | 16 +++---- src/Data.h | 16 +++---- src/Datastore.cpp | 10 ++-- src/Datastore.h | 10 ++-- src/DuplexHandler.cpp | 24 +++++----- src/DuplexHandler.h | 4 +- src/EventTable.cpp | 27 ++++++++++- src/EventTable.h | 2 +- src/grandeurtypes.cpp | 2 +- src/grandeurtypes.h | 104 ++++++++++++++++++++++++++++++++++++------ 10 files changed, 158 insertions(+), 57 deletions(-) diff --git a/src/Data.cpp b/src/Data.cpp index 0c99e57..6fd5c0d 100644 --- a/src/Data.cpp +++ b/src/Data.cpp @@ -18,7 +18,7 @@ Data::Data(String deviceID, DuplexHandler duplexHandler) { Data::Data() {} -void Data::get(const char* path, Callback callback) { +void Data::get(const char* path, Callback callback) { // Get data from server // Create a new json object JSONObject jsonObject; @@ -39,7 +39,7 @@ void Data::get(const char* path, Callback callback) { _duplex.send("/device/data/get", jsonString, callback); } -void Data::set(const char* path, JSONObject data, Callback callback) { +void Data::set(const char* path, JSONObject data, Callback callback) { // Set data to server // Create a new json object JSONObject jsonObject; @@ -63,7 +63,7 @@ void Data::set(const char* path, JSONObject data, Callback callback) _duplex.send("/device/data/set", jsonString, callback); } -void Data::set(const char* path, bool data, Callback callback) { +void Data::set(const char* path, bool data, Callback callback) { // Set data to server // Create a new json object JSONObject jsonObject; @@ -88,7 +88,7 @@ void Data::set(const char* path, bool data, Callback callback) { } -void Data::set(const char* path, int data, Callback callback) { +void Data::set(const char* path, int data, Callback callback) { // Set data to server // Create a new json object JSONObject jsonObject; @@ -112,7 +112,7 @@ void Data::set(const char* path, int data, Callback callback) { _duplex.send("/device/data/set", jsonString, callback); } -void Data::set(const char* path, long data, Callback callback) { +void Data::set(const char* path, long data, Callback callback) { // Set data to server // Create a new json object JSONObject jsonObject; @@ -136,7 +136,7 @@ void Data::set(const char* path, long data, Callback callback) { _duplex.send("/device/data/set", jsonString, callback); } -void Data::set(const char* path, double data, Callback callback) { +void Data::set(const char* path, double data, Callback callback) { // Set data to server // Create a new json object JSONObject jsonObject; @@ -160,7 +160,7 @@ void Data::set(const char* path, double data, Callback callback) { _duplex.send("/device/data/set", jsonString, callback); } -void Data::set(const char* path, const char* data, Callback callback) { +void Data::set(const char* path, const char* data, Callback callback) { // Set data to server // Create a new json object JSONObject jsonObject; @@ -185,7 +185,7 @@ void Data::set(const char* path, const char* data, Callback callback } -void Data::on(const char* path, Callback callback) { +void Data::on(const char* path, Callback callback) { // Place an event handler on path update // Create a new json object JSONObject jsonObject; diff --git a/src/Data.h b/src/Data.h index b06f5fc..9b2dc20 100644 --- a/src/Data.h +++ b/src/Data.h @@ -28,16 +28,16 @@ class Data { Data(); // Async getter/setter methods - void get(const char* path, Callback callback); - void set(const char* path, JSONObject data, Callback callback); - void set(const char* path, bool data, Callback callback); - void set(const char* path, int data, Callback callback); - void set(const char* path, long data, Callback callback); - void set(const char* path, double data, Callback callback); - void set(const char* path, const char* data, Callback callback); + void get(const char* path, Callback callback); + void set(const char* path, JSONObject data, Callback callback); + void set(const char* path, bool data, Callback callback); + void set(const char* path, int data, Callback callback); + void set(const char* path, long data, Callback callback); + void set(const char* path, double data, Callback callback); + void set(const char* path, const char* data, Callback callback); // Sync event handlers - void on(const char* path, Callback callback); + void on(const char* path, Callback callback); }; #endif \ No newline at end of file diff --git a/src/Datastore.cpp b/src/Datastore.cpp index 9f7a4c3..f5b98cb 100644 --- a/src/Datastore.cpp +++ b/src/Datastore.cpp @@ -26,7 +26,7 @@ Collection::Collection(String name, DuplexHandler duplexHandler) { _duplex = duplexHandler; } -void Collection::insert(JSONObject documents, Callback inserted) { +void Collection::insert(JSONObject documents, Callback inserted) { JSONObject jsonObject; char jsonString[PACKET_SIZE]; @@ -38,7 +38,7 @@ void Collection::insert(JSONObject documents, Callback inserted) { _duplex.send("/datastore/insert", jsonString, inserted); } -void Collection::remove(JSONObject filter, Callback removed) { +void Collection::remove(JSONObject filter, Callback removed) { JSONObject jsonObject; char jsonString[PACKET_SIZE]; @@ -50,7 +50,7 @@ void Collection::remove(JSONObject filter, Callback removed) { _duplex.send("/datastore/delete", jsonString, removed); } -void Collection::update(JSONObject filter, JSONObject update, Callback updated) { +void Collection::update(JSONObject filter, JSONObject update, Callback updated) { JSONObject jsonObject; char jsonString[PACKET_SIZE]; @@ -63,7 +63,7 @@ void Collection::update(JSONObject filter, JSONObject update, Callback searched) { +void Collection::search(JSONObject filter, JSONObject projection, int pageNumber, Callback searched) { Pipeline searchPipeline = Pipeline(_name, {}, _duplex).match(filter); if(projection == undefined) {} else { @@ -116,7 +116,7 @@ Pipeline Pipeline::sort(JSONObject specs) { return Pipeline(_collection, _query, _duplex); } -void Pipeline::execute(int pageNumber, Callback executed) { +void Pipeline::execute(int pageNumber, Callback executed) { JSONObject jsonObject; char jsonString[PACKET_SIZE]; diff --git a/src/Datastore.h b/src/Datastore.h index 5ec3565..a6a42ee 100644 --- a/src/Datastore.h +++ b/src/Datastore.h @@ -28,7 +28,7 @@ class Pipeline { Pipeline project(JSONObject specs); Pipeline group(JSONObject condition, JSONObject fields); Pipeline sort(JSONObject specs); - void execute(int pageNumber, Callback executed); + void execute(int pageNumber, Callback executed); }; class Collection { @@ -40,10 +40,10 @@ class Collection { // Collection constructor Collection(String name, DuplexHandler duplexHandler); // Methods - void insert(JSONObject documents, Callback inserted); - void remove(JSONObject filter, Callback removed); - void update(JSONObject filter, JSONObject update, Callback updated); - void search(JSONObject filter, JSONObject projection, int pageNumber, Callback searched); + void insert(JSONObject documents, Callback inserted); + void remove(JSONObject filter, Callback removed); + void update(JSONObject filter, JSONObject update, Callback updated); + void search(JSONObject filter, JSONObject projection, int pageNumber, Callback searched); Pipeline pipeline(void); }; diff --git a/src/DuplexHandler.cpp b/src/DuplexHandler.cpp index 8c4929d..2f3b711 100644 --- a/src/DuplexHandler.cpp +++ b/src/DuplexHandler.cpp @@ -87,7 +87,7 @@ void DuplexHandler::loop(bool valve) { } } -void DuplexHandler::send(const char* task, const char* payload, Callback callback) { +void DuplexHandler::send(const char* task, const char* payload, Callback callback) { // Check connection status if(_status != CONNECTED) { // Add to queue if not connected @@ -103,8 +103,8 @@ void DuplexHandler::send(const char* task, const char* payload, Callback updateHandler) { +void DuplexHandler::subscribe(const char* event, const char* payload, Callback updateHandler) { // Generate an id GrandeurID eventID = millis(); // Saving callback to eventsTable _subscriptions.insert(event, eventID, updateHandler); - _eventsTable.print(); - _subscriptions.print(); + // _eventsTable.print(); + // _subscriptions.print(); // Saving callback in event table with key send("/topic/subscribe", payload, NULL); @@ -183,7 +183,7 @@ void duplexEventHandler(WStype_t eventType, uint8_t* packet, size_t length) { return DuplexHandler::_connectionCallback(DuplexHandler::_status); case WStype_TEXT: - Serial.printf("%s\n", packet); + // Serial.printf("%s\n", packet); // When a duplex message is received. JSONObject messageObject = JSON.parse((char*) packet); @@ -203,8 +203,8 @@ void duplexEventHandler(WStype_t eventType, uint8_t* packet, size_t length) { std::string path((const char*) messageObject["payload"]["path"]); // Emit the event - DuplexHandler::_subscriptions.emit(event + "/" + path, messageObject["payload"]); - + DuplexHandler::_subscriptions.emit(event + "/" + path, messageObject["payload"]["update"]); + // Return return; } @@ -214,13 +214,13 @@ void duplexEventHandler(WStype_t eventType, uint8_t* packet, size_t length) { } // Fetching event callback function from the events Table - Callback callback = DuplexHandler::_eventsTable.findAndRemove( + Callback callback = DuplexHandler::_eventsTable.findAndRemove( (const char*) messageObject["header"]["task"], (GrandeurID) messageObject["header"]["id"] ); - DuplexHandler::_eventsTable.print(); - DuplexHandler::_subscriptions.print(); + // DuplexHandler::_eventsTable.print(); + // DuplexHandler::_subscriptions.print(); // If not found then simply return if(!callback) return; diff --git a/src/DuplexHandler.h b/src/DuplexHandler.h index 984b26c..88c29a1 100644 --- a/src/DuplexHandler.h +++ b/src/DuplexHandler.h @@ -49,10 +49,10 @@ class DuplexHandler { void ping(); // Function to send a generic duplex message. - static void send(const char* task, const char* payload, Callback callback); + static void send(const char* task, const char* payload, Callback callback); // Function to subscribe to a device topic. - void subscribe(const char* event, const char* payload, Callback updateHandler); + void subscribe(const char* event, const char* payload, Callback updateHandler); // Function to schedule an event handler for connection with Grandeur void onConnectionEvent(void connectionEventHandler(bool)); diff --git a/src/EventTable.cpp b/src/EventTable.cpp index 6db1265..1df5687 100644 --- a/src/EventTable.cpp +++ b/src/EventTable.cpp @@ -169,6 +169,9 @@ EventData EventTable::findAndRemove(EventKey key, EventID id) { } int EventTable::emit(EventKey key, JSONObject packet) { + // Cast packet as per type of packet + String type = JSON.typeof_(packet); + // Created a regex std::regex pattern("(" + key + ")(.*)"); @@ -181,7 +184,29 @@ int EventTable::emit(EventKey key, JSONObject packet) { // We will use regex to match the key of the block if (std::regex_match(p->key, pattern)) { // Then emit packet to callback - p->data(packet); + if (type == "boolean") { + // Cast as boolean + p->data((bool) packet); + } + else if (type == "number") { + // Figure out that if it is a double or not + if ((double) packet - (int) packet != 0) { + // Cast as double + p->data((double) packet); + } + else { + // Cast as int for now + p->data((int) packet); + } + } + else if (type == "string") { + // Cast as string + p->data((const char*) packet); + } + else if (type == "object" || type == "array") { + // Cast as object + p->data((JSONObject) packet); + } } // Keep moving diff --git a/src/EventTable.h b/src/EventTable.h index fecbada..5b5b19d 100644 --- a/src/EventTable.h +++ b/src/EventTable.h @@ -19,7 +19,7 @@ typedef GrandeurID EventID; //EventData -typedef Callback EventData; +typedef Callback EventData; // Event key typedef std::string EventKey; diff --git a/src/grandeurtypes.cpp b/src/grandeurtypes.cpp index 59c98d9..585c92b 100644 --- a/src/grandeurtypes.cpp +++ b/src/grandeurtypes.cpp @@ -24,7 +24,7 @@ Config::Config() { } // Object which stores the task while it is on queue -SendData::SendData(const char* task, const char* payload, Callback callback) { +SendData::SendData(const char* task, const char* payload, Callback callback) { strcpy(this->task, task); strcpy(this->payload, payload); this->callback = callback; diff --git a/src/grandeurtypes.h b/src/grandeurtypes.h index 0151e51..4bbd591 100644 --- a/src/grandeurtypes.h +++ b/src/grandeurtypes.h @@ -19,43 +19,119 @@ typedef JSONVar JSONObject; // Define Callback using template -template class Callback { private: // Create a private variable - void (*_c)(T); + void (*_cJSON)(JSONObject); + void (*_cBool)(bool); + void (*_cInt)(int); + void (*_cLong)(long); + void (*_cDouble)(double); + void (*_cStr)(const char*); public: // Default constructor will init the pointer Callback() { // We will init the context - _c = NULL; + _cJSON = NULL; + _cBool = NULL; + _cInt = NULL; + _cLong = NULL; + _cDouble = NULL; + _cStr = NULL; + } + + // Constructor to handle null + Callback(int c) { + // We will init the context + _cJSON = NULL; + _cBool = NULL; + _cInt = NULL; + _cLong = NULL; + _cDouble = NULL; + _cStr = NULL; } - // It will receive an function - Callback(void (*c)(T)) { + // For json callback + Callback(void (*c)(JSONObject)) { + // We will store it in context + _cJSON = c; + } + + // For bool type callback + Callback(void (*c)(bool)) { // We will store it in context - _c = c; + _cBool = c; + } + + // For int callback + Callback(void (*c)(int)) { + // We will store it in context + _cInt = c; + } + + // For long datatype + Callback(void (*c)(long)) { + // We will store it in context + _cLong = c; + } + + + // For double datatype + Callback(void (*c)(double)) { + // We will store it in context + _cDouble = c; + } + + // For handling strings + Callback(void (*c)(const char*)) { + // We will store it in context + _cStr = c; } // Then we will override the function call // operator to pass data to callback that we stored // in the context - void operator()(T data) { - // Call the function stored in context - _c(data); + void operator()(JSONObject data) { + // Transfer data to json callback + _cJSON(data); + } + + void operator()(bool data) { + // Transfer it to bool callback + _cBool(data); + } + + void operator()(int data) { + // Transfer data to int callback + _cInt(data); + } + + void operator()(long data) { + // Transfer data to long callback + _cLong(data); + } + + void operator()(double data) { + // Transfer data to double callback + _cDouble(data); + } + + void operator()(const char* data) { + // Transfer data to string callback + _cStr(data); } // Override bool operator not bool operator!() { - // Return true if callback was set - if (!_c) return true; + // Return true if none of the callbacks are set + if (!_cJSON && !_cBool && !_cInt && !_cLong && !_cDouble && !_cStr) return true; else return false; } }; // Define send function -typedef void (*Send)(const char* task, const char* payload, Callback callback); +typedef void (*Send)(const char* task, const char* payload, Callback callback); // Define Grandeur ID typedef long GrandeurID; @@ -76,13 +152,13 @@ class SendData { public: char task[TASK_SIZE]; char payload[PACKET_SIZE]; - Callback callback; + Callback callback; // Constructor SendData( const char* task, const char* payload, - Callback callback + Callback callback ); }; From 17bd3d22d9791c1ae9850fe8b5c47d36dee357d1 Mon Sep 17 00:00:00 2001 From: moizhusnain Date: Fri, 29 Jan 2021 04:29:18 +0500 Subject: [PATCH 04/11] Fixed callback and queue Callback is now based on Var, plus overloading is just on const char* We aren't handling types in callback for now Fixed queue, had to had another datastructure --- keywords.txt | 2 +- src/Data.cpp | 130 +------------------------------ src/Data.h | 7 +- src/Datastore.cpp | 106 +++++++++++++++++++------- src/Datastore.h | 59 +++++++++++---- src/DuplexHandler.cpp | 71 ++++++++++++----- src/DuplexHandler.h | 7 ++ src/EventQueue.cpp | 172 ++++++++++++++++++++++++++++++++++++++++++ src/EventQueue.h | 72 ++++++++++++++++++ src/EventTable.cpp | 38 ++-------- src/EventTable.h | 11 +-- src/grandeurmacros.h | 3 - src/grandeurtypes.cpp | 7 -- src/grandeurtypes.h | 136 +++++++++------------------------ 14 files changed, 475 insertions(+), 346 deletions(-) create mode 100644 src/EventQueue.cpp create mode 100644 src/EventQueue.h diff --git a/keywords.txt b/keywords.txt index ee99a23..9c75cfc 100644 --- a/keywords.txt +++ b/keywords.txt @@ -16,7 +16,7 @@ Data KEYWORD3 ####################################### Callback KEYWORD1 -JSONObject KEYWORD1 +Var KEYWORD1 ####################################### # Methods and Functions ####################################### diff --git a/src/Data.cpp b/src/Data.cpp index 6fd5c0d..c176c2c 100644 --- a/src/Data.cpp +++ b/src/Data.cpp @@ -21,7 +21,7 @@ Data::Data() {} void Data::get(const char* path, Callback callback) { // Get data from server // Create a new json object - JSONObject jsonObject; + Var jsonObject; // Create packet char jsonString[PACKET_SIZE]; @@ -39,10 +39,10 @@ void Data::get(const char* path, Callback callback) { _duplex.send("/device/data/get", jsonString, callback); } -void Data::set(const char* path, JSONObject data, Callback callback) { +void Data::set(const char* path, Var data, Callback callback) { // Set data to server // Create a new json object - JSONObject jsonObject; + Var jsonObject; // Create packet char jsonString[PACKET_SIZE]; @@ -63,132 +63,10 @@ void Data::set(const char* path, JSONObject data, Callback callback) { _duplex.send("/device/data/set", jsonString, callback); } -void Data::set(const char* path, bool data, Callback callback) { - // Set data to server - // Create a new json object - JSONObject jsonObject; - - // Create packet - char jsonString[PACKET_SIZE]; - - // Add device id - jsonObject["deviceID"] = _deviceID; - - // Add path - jsonObject["path"] = path; - - // Add data - jsonObject["data"] = data; - - // Conver the object to string - JSON.stringify(jsonObject).toCharArray(jsonString, PACKET_SIZE); - - // Send - _duplex.send("/device/data/set", jsonString, callback); -} - - -void Data::set(const char* path, int data, Callback callback) { - // Set data to server - // Create a new json object - JSONObject jsonObject; - - // Create packet - char jsonString[PACKET_SIZE]; - - // Add device id - jsonObject["deviceID"] = _deviceID; - - // Add path - jsonObject["path"] = path; - - // Add data - jsonObject["data"] = data; - - // Conver the object to string - JSON.stringify(jsonObject).toCharArray(jsonString, PACKET_SIZE); - - // Send - _duplex.send("/device/data/set", jsonString, callback); -} - -void Data::set(const char* path, long data, Callback callback) { - // Set data to server - // Create a new json object - JSONObject jsonObject; - - // Create packet - char jsonString[PACKET_SIZE]; - - // Add device id - jsonObject["deviceID"] = _deviceID; - - // Add path - jsonObject["path"] = path; - - // Add data - jsonObject["data"] = data; - - // Conver the object to string - JSON.stringify(jsonObject).toCharArray(jsonString, PACKET_SIZE); - - // Send - _duplex.send("/device/data/set", jsonString, callback); -} - -void Data::set(const char* path, double data, Callback callback) { - // Set data to server - // Create a new json object - JSONObject jsonObject; - - // Create packet - char jsonString[PACKET_SIZE]; - - // Add device id - jsonObject["deviceID"] = _deviceID; - - // Add path - jsonObject["path"] = path; - - // Add data - jsonObject["data"] = data; - - // Conver the object to string - JSON.stringify(jsonObject).toCharArray(jsonString, PACKET_SIZE); - - // Send - _duplex.send("/device/data/set", jsonString, callback); -} - -void Data::set(const char* path, const char* data, Callback callback) { - // Set data to server - // Create a new json object - JSONObject jsonObject; - - // Create packet - char jsonString[PACKET_SIZE]; - - // Add device id - jsonObject["deviceID"] = _deviceID; - - // Add path - jsonObject["path"] = path; - - // Add data - jsonObject["data"] = data; - - // Conver the object to string - JSON.stringify(jsonObject).toCharArray(jsonString, PACKET_SIZE); - - // Send - _duplex.send("/device/data/set", jsonString, callback); -} - - void Data::on(const char* path, Callback callback) { // Place an event handler on path update // Create a new json object - JSONObject jsonObject; + Var jsonObject; // Create packet char jsonString[PACKET_SIZE]; diff --git a/src/Data.h b/src/Data.h index 9b2dc20..763826c 100644 --- a/src/Data.h +++ b/src/Data.h @@ -29,12 +29,7 @@ class Data { // Async getter/setter methods void get(const char* path, Callback callback); - void set(const char* path, JSONObject data, Callback callback); - void set(const char* path, bool data, Callback callback); - void set(const char* path, int data, Callback callback); - void set(const char* path, long data, Callback callback); - void set(const char* path, double data, Callback callback); - void set(const char* path, const char* data, Callback callback); + void set(const char* path, Var data, Callback callback); // Sync event handlers void on(const char* path, Callback callback); diff --git a/src/Datastore.cpp b/src/Datastore.cpp index f5b98cb..b5167c4 100644 --- a/src/Datastore.cpp +++ b/src/Datastore.cpp @@ -12,119 +12,169 @@ #include "Datastore.h" Datastore::Datastore(DuplexHandler duplexHandler) { + // Store reference to duplex into context _duplex = duplexHandler; } -Datastore::Datastore() {} +Datastore::Datastore() { + // Default constructor +} Collection Datastore::collection(String name) { + // Return a reference to collection object return Collection(name, _duplex); } Collection::Collection(String name, DuplexHandler duplexHandler) { + // Store name of collection and reference to object _name = name; _duplex = duplexHandler; } -void Collection::insert(JSONObject documents, Callback inserted) { - JSONObject jsonObject; +void Collection::insert(Var documents, Callback inserted) { + // Insert documents to datastore + Var jsonObject; + + // Define string char jsonString[PACKET_SIZE]; + // Append collection name and documents jsonObject["collection"] = _name; jsonObject["documents"] = documents; + // Convert to string JSON.stringify(jsonObject).toCharArray(jsonString, PACKET_SIZE); + // Send request to server _duplex.send("/datastore/insert", jsonString, inserted); } -void Collection::remove(JSONObject filter, Callback removed) { - JSONObject jsonObject; - char jsonString[PACKET_SIZE]; +void Collection::remove(Var filter, Callback removed) { + // Remove documents from datastore + Var jsonObject; + // Define string + char jsonString[PACKET_SIZE]; + + // Append collection name and filter jsonObject["collection"] = _name; jsonObject["filter"] = filter; - - JSON.stringify(jsonObject).toCharArray(jsonString, PACKET_SIZE); + // Convert to string + JSON.stringify(jsonObject).toCharArray(jsonString, PACKET_SIZE); + + // Send request to server _duplex.send("/datastore/delete", jsonString, removed); } -void Collection::update(JSONObject filter, JSONObject update, Callback updated) { - JSONObject jsonObject; - char jsonString[PACKET_SIZE]; +void Collection::update(Var filter, Var update, Callback updated) { + // Update document from datastore + Var jsonObject; + // Define string + char jsonString[PACKET_SIZE]; + + // Append collection name, filter and update jsonObject["collection"] = _name; jsonObject["filter"] = filter; - jsonObject["update"] = update; - + + // Convert to string JSON.stringify(jsonObject).toCharArray(jsonString, PACKET_SIZE); + // Send request to server _duplex.send("/datastore/update", jsonString, updated); } -void Collection::search(JSONObject filter, JSONObject projection, int pageNumber, Callback searched) { +void Collection::search(Var filter, Var projection, int nPage, Callback searched) { + // Basically it will use pipeline Pipeline searchPipeline = Pipeline(_name, {}, _duplex).match(filter); - if(projection == undefined) {} + + // Add project stage if provided + if(projection == undefined); else { searchPipeline = searchPipeline.project(projection); } - return searchPipeline.execute(pageNumber, searched); + // Execute the pipeline + return searchPipeline.execute(nPage, searched); } Pipeline Collection::pipeline(void) { + // Return a reference to pipeline return Pipeline(_name, undefined, _duplex); } -Pipeline::Pipeline(String collectionName, JSONObject query, DuplexHandler duplexHandler) { - _collection = collectionName; +Pipeline::Pipeline(String collection, Var query, DuplexHandler duplexHandler) { + // Setup the context + _collection = collection; _query = query; _duplex = duplexHandler; } -Pipeline Pipeline::match(JSONObject filter) { +Pipeline Pipeline::match(Var filter) { + // Add match stage to the pipeline int stage = _query.length() + 1; + + // Add type and filter _query[stage]["type"] = "match"; _query[stage]["filter"] = filter; + // Return reference to pipeline to basically help in chaining return Pipeline(_collection, _query, _duplex); } -Pipeline Pipeline::project(JSONObject specs) { +Pipeline Pipeline::project(Var specs) { + // Add project stage to the pipeline int stage = _query.length() + 1; - _query[stage]["type"] = "project"; + + // Add type and specs + _query[stage]["type"] = "match"; _query[stage]["specs"] = specs; + // Return reference to pipeline to basically help in chaining return Pipeline(_collection, _query, _duplex); } -Pipeline Pipeline::group(JSONObject condition, JSONObject fields) { +Pipeline Pipeline::group(Var condition, Var fields) { + // Add group stage to the pipeline int stage = _query.length() + 1; - _query[stage]["type"] = "group"; + + // Add type, condition and fields + _query[stage]["type"] = "match"; _query[stage]["condition"] = condition; _query[stage]["fields"] = fields; + // Return reference to pipeline to basically help in chaining return Pipeline(_collection, _query, _duplex); } -Pipeline Pipeline::sort(JSONObject specs) { +Pipeline Pipeline::sort(Var specs) { + // Add sort stage to the pipeline int stage = _query.length() + 1; - _query[stage]["type"] = "sort"; + + // Add type and specs + _query[stage]["type"] = "match"; _query[stage]["specs"] = specs; + // Return reference to pipeline to basically help in chaining return Pipeline(_collection, _query, _duplex); } -void Pipeline::execute(int pageNumber, Callback executed) { - JSONObject jsonObject; +void Pipeline::execute(int nPage, Callback executed) { + // Define an object + Var jsonObject; + + // Define string char jsonString[PACKET_SIZE]; + // Formulate query jsonObject["collection"] = _collection; jsonObject["pipeline"] = _query; - jsonObject["pageNumber"] = pageNumber; + jsonObject["nPage"] = nPage; + // Convert query to string JSON.stringify(jsonObject).toCharArray(jsonString, PACKET_SIZE); + // Send to server _duplex.send("/datastore/pipeline", jsonString, executed); } diff --git a/src/Datastore.h b/src/Datastore.h index a6a42ee..74cf481 100644 --- a/src/Datastore.h +++ b/src/Datastore.h @@ -17,45 +17,76 @@ class Pipeline { // Class for a datastore collection private: + // Dedine collection name String _collection; - JSONObject _query; + + // Variable to store query + Var _query; + + // To store reference of duplex DuplexHandler _duplex; + public: // Collection constructor - Pipeline(String collectionName, JSONObject query, DuplexHandler duplexHandler); - // Methods - Pipeline match(JSONObject filter); - Pipeline project(JSONObject specs); - Pipeline group(JSONObject condition, JSONObject fields); - Pipeline sort(JSONObject specs); - void execute(int pageNumber, Callback executed); + Pipeline(String collection, Var query, DuplexHandler duplexHandler); + + // Method to add match stage + Pipeline match(Var filter); + + // Function to add project stage + Pipeline project(Var specs); + + // Function to add group stage + Pipeline group(Var condition, Var fields); + + // Function to add sort stage to query + Pipeline sort(Var specs); + + // Execute the query by sending function + void execute(int nPage, Callback executed); }; class Collection { // Class for a datastore collection private: + // Define name of collection String _name; + + // Store duplex handler reference DuplexHandler _duplex; + public: // Collection constructor Collection(String name, DuplexHandler duplexHandler); - // Methods - void insert(JSONObject documents, Callback inserted); - void remove(JSONObject filter, Callback removed); - void update(JSONObject filter, JSONObject update, Callback updated); - void search(JSONObject filter, JSONObject projection, int pageNumber, Callback searched); + + // Function to insert document to a collection + void insert(Var documents, Callback inserted); + + // Function to remove document from a collection + void remove(Var filter, Callback removed); + + // Function to update a document + void update(Var filter, Var update, Callback updated); + + // Function to perform a search + void search(Var filter, Var projection, int nPage, Callback searched); + + // Constructor Pipeline pipeline(void); }; class Datastore { // Class for handling datastore related functions private: + // Variable to store duplex reference DuplexHandler _duplex; + public: // Datastore constructor Datastore(DuplexHandler duplexHandler); Datastore(); - // Methods + + // Method to get reference to constructor Collection collection(String name); }; diff --git a/src/DuplexHandler.cpp b/src/DuplexHandler.cpp index 2f3b711..8db5425 100644 --- a/src/DuplexHandler.cpp +++ b/src/DuplexHandler.cpp @@ -17,16 +17,13 @@ WebSocketsClient client; // Init ping counter unsigned long millisCounterForPing = 0; -// Define queue size -size_t sendQueueSize = 0; - -// Create an array equal to max send queue size -SendData* sendQueue[SENDQUEUE_SIZE] = {}; - // Init status handler and variable short DuplexHandler::_status = DISCONNECTED; void (*DuplexHandler::_connectionCallback)(bool) = [](bool connectionEventHandler) {}; +// Define a queue +EventQueue DuplexHandler::_queue; + // Create a new event table and subscriptions EventTable DuplexHandler::_eventsTable; EventTable DuplexHandler::_subscriptions; @@ -87,22 +84,48 @@ void DuplexHandler::loop(bool valve) { } } -void DuplexHandler::send(const char* task, const char* payload, Callback callback) { +// Define the handle function +void DuplexHandler::handle(EventID id, EventKey key, EventPayload payload, Callback callback) { // Check connection status if(_status != CONNECTED) { - // Add to queue if not connected - sendQueue[sendQueueSize++] = new SendData(task, payload, callback); return ; } // Create packet char packet[PACKET_SIZE]; + // Saving callback to eventsTable + _eventsTable.insert(key, id, callback); + // Serial.println("On handle"); + // _eventsTable.print(); + // _subscriptions.print(); + + // Formatting the packet + snprintf(packet, PACKET_SIZE, "{\"header\": {\"id\": %lu, \"task\": \"%s\"}, \"payload\": %s}", id, key.c_str(), payload.c_str()); + + // Sending to server + client.sendTXT(packet); +} + +void DuplexHandler::send(const char* task, const char* payload, Callback callback) { // Generate packet id - GrandeurID packetID = millis(); + gID packetID = micros(); + + // Check connection status + if(_status != CONNECTED) { + // Append the packet to queue + _queue.push(packetID, task, payload, callback); + // Serial.println("Stack to queue"); + // _queue.print(); + return ; + } + + // Create packet + char packet[PACKET_SIZE]; // Saving callback to eventsTable _eventsTable.insert(task, packetID, callback); + // Serial.println("On send"); // _eventsTable.print(); // _subscriptions.print(); @@ -115,10 +138,11 @@ void DuplexHandler::send(const char* task, const char* payload, Callback callbac void DuplexHandler::subscribe(const char* event, const char* payload, Callback updateHandler) { // Generate an id - GrandeurID eventID = millis(); + gID eventID = micros(); // Saving callback to eventsTable _subscriptions.insert(event, eventID, updateHandler); + // Serial.println("On subscribe"); // _eventsTable.print(); // _subscriptions.print(); @@ -126,7 +150,6 @@ void DuplexHandler::subscribe(const char* event, const char* payload, Callback u send("/topic/subscribe", payload, NULL); } - void DuplexHandler::ping() { // Ping handler if(_status == CONNECTED) { @@ -134,7 +157,7 @@ void DuplexHandler::ping() { char packet[PING_PACKET_SIZE]; // Create id - GrandeurID packetID = millis(); + gID packetID = millis(); // Saving callback to eventsTable _eventsTable.insert("ping", packetID, NULL); @@ -166,10 +189,10 @@ void duplexEventHandler(WStype_t eventType, uint8_t* packet, size_t length) { // Resetting ping millis counter millisCounterForPing = millis(); - // Sending all queued messages - for(int i = 0; i < sendQueueSize; i++) { - DuplexHandler::send(sendQueue[i]->task, sendQueue[i]->payload, sendQueue[i]->callback); - } + // Handle the queued events + DuplexHandler::_queue.forEach(DuplexHandler::handle); + + // Then send return ; case WStype_DISCONNECTED: @@ -186,7 +209,7 @@ void duplexEventHandler(WStype_t eventType, uint8_t* packet, size_t length) { // Serial.printf("%s\n", packet); // When a duplex message is received. - JSONObject messageObject = JSON.parse((char*) packet); + Var messageObject = JSON.parse((char*) packet); // Handle parsing errors if (JSON.typeof(messageObject) == "undefined") { @@ -203,7 +226,7 @@ void duplexEventHandler(WStype_t eventType, uint8_t* packet, size_t length) { std::string path((const char*) messageObject["payload"]["path"]); // Emit the event - DuplexHandler::_subscriptions.emit(event + "/" + path, messageObject["payload"]["update"]); + DuplexHandler::_subscriptions.emit(event + "/" + path, messageObject["payload"]["update"], messageObject["payload"]["path"]); // Return return; @@ -216,15 +239,23 @@ void duplexEventHandler(WStype_t eventType, uint8_t* packet, size_t length) { // Fetching event callback function from the events Table Callback callback = DuplexHandler::_eventsTable.findAndRemove( (const char*) messageObject["header"]["task"], - (GrandeurID) messageObject["header"]["id"] + (gID) messageObject["header"]["id"] ); + + // Serial.println("On message"); // DuplexHandler::_eventsTable.print(); // DuplexHandler::_subscriptions.print(); // If not found then simply return if(!callback) return; + // Remove the packet if it was queued + // because the ack has been received + DuplexHandler::_queue.remove((long) messageObject["header"]["id"]); + // Serial.println("On remove"); + // DuplexHandler::_queue.print(); + // Or otherwise resolve the event return callback(messageObject["payload"]); } diff --git a/src/DuplexHandler.h b/src/DuplexHandler.h index 88c29a1..38ffa80 100644 --- a/src/DuplexHandler.h +++ b/src/DuplexHandler.h @@ -10,6 +10,7 @@ // Including headers #include "EventTable.h" +#include "EventQueue.h" #include "grandeurtypes.h" #include "grandeurmacros.h" #include "arduinoWebSockets/WebSocketsClient.h" @@ -28,6 +29,9 @@ class DuplexHandler { // Connection state variable static short _status; + // Event Queue + static EventQueue _queue; + // Events Table static EventTable _eventsTable; @@ -37,6 +41,9 @@ class DuplexHandler { // Container for connection callback static void (*_connectionCallback)(bool); + // Define function to handle the queued events + static void handle(EventID id, EventKey key, EventPayload payload, Callback callback); + public: // Constructor DuplexHandler(Config config); diff --git a/src/EventQueue.cpp b/src/EventQueue.cpp new file mode 100644 index 0000000..f17f184 --- /dev/null +++ b/src/EventQueue.cpp @@ -0,0 +1,172 @@ +/** + * @file EventQueue.cpp + * @date 24.03.2020 + * @author Grandeur Technologies + * + * Copyright (c) 2019 Grandeur Technologies LLP. All rights reserved. + * This file is part of the Arduino SDK for Grandeur. + * + */ + +// Inlcude event table +#include +#include + +// Implement event queue block +EventQueueEntry::EventQueueEntry(EventID id, EventKey key, EventPayload payload, Callback callback) { + this->id = id; + this->key = key; + this->payload = payload; + this->callback = callback; + this->next = NULL; +} + +EventQueueEntry::EventQueueEntry(int k) { + this->id = NULL; +} + +bool EventQueueEntry::operator!() { + // If the queue block was not set as null + // then return true + if (id != NULL) { + return true; + } + + // Otherwise return false + return false; +} + +// Implement event queue constructor +EventQueue::EventQueue() { + // Init queue as null + queue = NULL; +} + +int EventQueue::push(EventID id, EventKey key, EventPayload payload, Callback callback) { + // We will insert a block at the head + // Store the reference to next of queue + EventQueueEntry* p = queue; + + // Then assign the queue to new block + queue = new EventQueueEntry(id, key, payload, callback); + + // Then assign queue next of old block + queue->next = p; + + // Plus the length + _length++; + + return 0; +} + +int EventQueue::remove(EventID id) { + // Check if bucket is empty + if(queue == NULL) { + // which means the entry does not exist + return -1; + } + + // If the id was found in first block + if(queue->id == id) { + // Pull the chain backwards + EventQueueEntry* p = queue; + queue = queue->next; + + // and delete it + delete p; + return 0; + } + + // If the bucket is not empty, + // getting ready for traversing the chain + EventQueueEntry* p = queue; + + // While not the end has reached + while (p->next != NULL) { + // Break if the next block has the id we need + if (p->next->id == id) break; + + // Keep moving + p = p->next; + } + + // Handle case where we reached the end + if (p->next == NULL) { + // No element is found + return -1; + } + + // If the element is found + // Then pull the chain backward + EventQueueEntry* q = p->next; + p->next = p->next->next; + + // and delete it + delete q; + return 0; +} + +void EventQueue::forEach(void (*callback)(EventID, EventKey, EventPayload, Callback)) { + // Loop over the queue + EventQueueEntry* p = queue; + + // While not the end + while (p != NULL) { + // Call the callback + callback(p->id, p->key, p->payload, p->callback); + + // Move to next + p = p->next; + } +} + +int EventQueue::length() { + // Return length of queue + return _length; +} + +void EventQueue::print() { + // Loop over the queue + EventQueueEntry* p = queue; + + // Print header + Serial.printf("\n*******Queue*******\n"); + + // While not the end + while (p != NULL) { + // Print the id + Serial.printf("%s\n", p->key.c_str()); + + p = p->next; + } + + // Print footer + Serial.printf("*******************\n"); +} + +void EventQueue::clear() { + // Function to delete all blocks + // If the bucket is not empty, + // getting ready for traversing the chain + EventQueueEntry* p = queue; + + // While not the end has reached + while (p != NULL) { + // Copy block address to a pointer + EventQueueEntry* next = p->next; + + // delete p + delete p; + + // Move next + p = next; + } + + // Mark queue as empty + queue = NULL; + _length = 0; +} + +EventQueue::~EventQueue() { + clear(); +} \ No newline at end of file diff --git a/src/EventQueue.h b/src/EventQueue.h new file mode 100644 index 0000000..af3d04c --- /dev/null +++ b/src/EventQueue.h @@ -0,0 +1,72 @@ +/** + * @file EventQueue.h + * @date 29.01.2021 + * @author Grandeur Technologies + * + * Copyright (c) 2019 Grandeur Technologies LLP. All rights reserved. + * This file is part of the Arduino SDK for Grandeur. + * + */ + +#include +#include +#include "grandeurtypes.h" + +#ifndef EVENTQUEUE_H_ +#define EVENTQUEUE_H_ + +// Event table entry is the block which represents +// an event +class EventQueueEntry { + public: + EventID id; + EventKey key; + EventPayload payload; + Callback callback; + EventQueueEntry* next; + + // Constructor + EventQueueEntry(EventID id, EventKey key, EventPayload payload, Callback callback); + EventQueueEntry(int k); + + // Override bool operator not + bool operator!(); +}; + +// The main class +class EventQueue { + private: + // Define queue + EventQueueEntry *queue; + + // Queue length + int _length = 0; + + public: + // Constructor for a table + EventQueue(); + + // Method to insert an entry into the queue + int push(EventID id, EventKey key, EventPayload payload, Callback callback); + + // Method to remove an entry + int remove(EventID id); + + // Method to loop over the elements in queue + // and return the entry in callback + void forEach(void (*callback)(EventID, EventKey, EventPayload, Callback)); + + // Function return queue size + int length(); + + // Print queue + void print(); + + // Method to clear queue + void clear(); + + // Destructor for a queue + ~EventQueue(); +}; + +#endif \ No newline at end of file diff --git a/src/EventTable.cpp b/src/EventTable.cpp index 1df5687..aa9625e 100644 --- a/src/EventTable.cpp +++ b/src/EventTable.cpp @@ -28,7 +28,6 @@ EventTable::EventTable() { } int EventTable::insert(EventKey key, EventID id, EventData data) { - // If bucket is empty, if(table == NULL) { // creating the first entry @@ -168,45 +167,20 @@ EventData EventTable::findAndRemove(EventKey key, EventID id) { return data; } -int EventTable::emit(EventKey key, JSONObject packet) { - // Cast packet as per type of packet - String type = JSON.typeof_(packet); - - // Created a regex - std::regex pattern("(" + key + ")(.*)"); - +int EventTable::emit(EventKey key, Var packet, const char* path) { // If the bucket is not empty, // getting ready for traversing the chain EventTableEntry* p = table; // While not the end has reached while (p != NULL) { + // Define pattern + std::regex pattern("(" + p->key + ")(.*)"); + // We will use regex to match the key of the block - if (std::regex_match(p->key, pattern)) { + if (std::regex_match(key, pattern)) { // Then emit packet to callback - if (type == "boolean") { - // Cast as boolean - p->data((bool) packet); - } - else if (type == "number") { - // Figure out that if it is a double or not - if ((double) packet - (int) packet != 0) { - // Cast as double - p->data((double) packet); - } - else { - // Cast as int for now - p->data((int) packet); - } - } - else if (type == "string") { - // Cast as string - p->data((const char*) packet); - } - else if (type == "object" || type == "array") { - // Cast as object - p->data((JSONObject) packet); - } + p->data(packet, path); } // Keep moving diff --git a/src/EventTable.h b/src/EventTable.h index 5b5b19d..13d7c57 100644 --- a/src/EventTable.h +++ b/src/EventTable.h @@ -15,15 +15,6 @@ #ifndef EVENTTABLE_H_ #define EVENTTABLE_H_ -// EventID -typedef GrandeurID EventID; - -//EventData -typedef Callback EventData; - -// Event key -typedef std::string EventKey; - // Event table entry is the block which represents // an event class EventTableEntry { @@ -57,7 +48,7 @@ class EventTable { EventData findAndRemove(EventKey key, EventID id); // Method to send some data to all callbacks at a key - int emit(EventKey key, JSONObject packet); + int emit(EventKey key, Var packet, const char* path); // Print table entreis void print(); diff --git a/src/grandeurmacros.h b/src/grandeurmacros.h index a435697..9d824ad 100644 --- a/src/grandeurmacros.h +++ b/src/grandeurmacros.h @@ -32,9 +32,6 @@ #define PING_PACKET_SIZE 64 #define TASK_SIZE 32 -// Send Queue Size -#define SENDQUEUE_SIZE 16 - // Ping interval in milliseconds #define PING_INTERVAL 25000 diff --git a/src/grandeurtypes.cpp b/src/grandeurtypes.cpp index 585c92b..fa67d29 100644 --- a/src/grandeurtypes.cpp +++ b/src/grandeurtypes.cpp @@ -21,11 +21,4 @@ Config::Config(String apiKey, String token) { Config::Config() { this->apiKey = ""; this->token = ""; -} - -// Object which stores the task while it is on queue -SendData::SendData(const char* task, const char* payload, Callback callback) { - strcpy(this->task, task); - strcpy(this->payload, payload); - this->callback = callback; } \ No newline at end of file diff --git a/src/grandeurtypes.h b/src/grandeurtypes.h index 4bbd591..bd110e2 100644 --- a/src/grandeurtypes.h +++ b/src/grandeurtypes.h @@ -16,125 +16,79 @@ #define GRANDEURTYPES_H_ // Include json -typedef JSONVar JSONObject; +typedef JSONVar Var; // Define Callback using template class Callback { private: // Create a private variable - void (*_cJSON)(JSONObject); - void (*_cBool)(bool); - void (*_cInt)(int); - void (*_cLong)(long); - void (*_cDouble)(double); - void (*_cStr)(const char*); + void (*_c)(Var); + void (*_cWStr)(Var, const char*); public: // Default constructor will init the pointer Callback() { // We will init the context - _cJSON = NULL; - _cBool = NULL; - _cInt = NULL; - _cLong = NULL; - _cDouble = NULL; - _cStr = NULL; + _c = NULL; + _cWStr = NULL; } - // Constructor to handle null - Callback(int c) { + Callback(int ptr) { // We will init the context - _cJSON = NULL; - _cBool = NULL; - _cInt = NULL; - _cLong = NULL; - _cDouble = NULL; - _cStr = NULL; + _c = NULL; + _cWStr = NULL; } // For json callback - Callback(void (*c)(JSONObject)) { + Callback(void (*c)(Var)) { // We will store it in context - _cJSON = c; + _c = c; } - // For bool type callback - Callback(void (*c)(bool)) { + Callback(void (*c)(Var, const char*)) { // We will store it in context - _cBool = c; - } - - // For int callback - Callback(void (*c)(int)) { - // We will store it in context - _cInt = c; - } - - // For long datatype - Callback(void (*c)(long)) { - // We will store it in context - _cLong = c; - } - - - // For double datatype - Callback(void (*c)(double)) { - // We will store it in context - _cDouble = c; - } - - // For handling strings - Callback(void (*c)(const char*)) { - // We will store it in context - _cStr = c; + _cWStr = c; } // Then we will override the function call // operator to pass data to callback that we stored // in the context - void operator()(JSONObject data) { - // Transfer data to json callback - _cJSON(data); - } - - void operator()(bool data) { - // Transfer it to bool callback - _cBool(data); - } - - void operator()(int data) { - // Transfer data to int callback - _cInt(data); + void operator()(Var data) { + // Transfer data callback + _c(data); } - void operator()(long data) { - // Transfer data to long callback - _cLong(data); - } - - void operator()(double data) { - // Transfer data to double callback - _cDouble(data); - } - - void operator()(const char* data) { - // Transfer data to string callback - _cStr(data); + // Overload for with string + void operator()(Var data, const char* path) { + // Transfer data callback with string + _cWStr(data, path); } // Override bool operator not bool operator!() { - // Return true if none of the callbacks are set - if (!_cJSON && !_cBool && !_cInt && !_cLong && !_cDouble && !_cStr) return true; + // Return true if the callback is not set + if (!_c && !_cWStr) return true; else return false; } }; -// Define send function -typedef void (*Send)(const char* task, const char* payload, Callback callback); - // Define Grandeur ID -typedef long GrandeurID; +typedef long gID; + +// EventID +typedef gID EventID; + +//EventData +typedef Callback EventData; + +// Event key +typedef std::string EventKey; + +// Event payload +typedef std::string EventPayload; + +// Event key +typedef std::string EventKey; // Config class for storing configurations of connection class Config { @@ -146,20 +100,4 @@ class Config { Config(String apiKey, String token); Config(); }; - -// Class for Send Queue Data -class SendData { - public: - char task[TASK_SIZE]; - char payload[PACKET_SIZE]; - Callback callback; - - // Constructor - SendData( - const char* task, - const char* payload, - Callback callback - ); -}; - #endif \ No newline at end of file From ecc3c03b2934dc8499c6e971264fb9c5036fc090 Mon Sep 17 00:00:00 2001 From: moizhusnain Date: Fri, 29 Jan 2021 19:00:56 +0500 Subject: [PATCH 05/11] Fixed backward compatibility issue --- src/DuplexHandler.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/DuplexHandler.cpp b/src/DuplexHandler.cpp index 8db5425..974eb91 100644 --- a/src/DuplexHandler.cpp +++ b/src/DuplexHandler.cpp @@ -225,6 +225,9 @@ void duplexEventHandler(WStype_t eventType, uint8_t* packet, size_t length) { std::string event((const char*) messageObject["payload"]["event"]); std::string path((const char*) messageObject["payload"]["path"]); + // Handle the backward compatibility case + if (event == "deviceParms" || event == "deviceSummary") event = "data"; + // Emit the event DuplexHandler::_subscriptions.emit(event + "/" + path, messageObject["payload"]["update"], messageObject["payload"]["path"]); From e76fb1f06162a77dbe50d50dcd5365d64f255bf8 Mon Sep 17 00:00:00 2001 From: moizhusnain Date: Sat, 30 Jan 2021 00:30:46 +0500 Subject: [PATCH 06/11] Now handling type casting in callback The callback can be typed or can be var In case of var, it will receive update without casting or otherwise the data will be casted or error will be returned --- src/EventTable.cpp | 47 +++++++++++- src/grandeurtypes.h | 169 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 203 insertions(+), 13 deletions(-) diff --git a/src/EventTable.cpp b/src/EventTable.cpp index aa9625e..072a88d 100644 --- a/src/EventTable.cpp +++ b/src/EventTable.cpp @@ -168,6 +168,9 @@ EventData EventTable::findAndRemove(EventKey key, EventID id) { } int EventTable::emit(EventKey key, Var packet, const char* path) { + // Cast packet as per type of packet + String type = JSON.typeof_(packet); + // If the bucket is not empty, // getting ready for traversing the chain EventTableEntry* p = table; @@ -180,9 +183,49 @@ int EventTable::emit(EventKey key, Var packet, const char* path) { // We will use regex to match the key of the block if (std::regex_match(key, pattern)) { // Then emit packet to callback - p->data(packet, path); + // Check the callback type + if (p->data.type() == "object") { + // The callback receives an object + // so we don't to do the type conversion + // Send with casting as Var + p->data((Var) packet, path); + } + else { + // Packet was boolean + if (type == "boolean") { + // Cast as boolean + p->data((bool) packet, path); + + } + + // Packet is number + else if (type == "number") { + // Figure out that if it is a double or int + if ((double) packet - (int) packet != 0) + // Cast as double + p->data((double) packet, path); + + else + // Cast as int + p->data((int) packet, path); + + } + + // Packet was string + else if (type == "string") { + // Cast as string + p->data((const char*) packet, path); + + } + + // Packet was object or array + else if (type == "object" || type == "array") { + // Send with casting as Var + p->data((Var) packet, path); + + } + } } - // Keep moving p = p->next; } diff --git a/src/grandeurtypes.h b/src/grandeurtypes.h index bd110e2..36fad2e 100644 --- a/src/grandeurtypes.h +++ b/src/grandeurtypes.h @@ -22,52 +22,199 @@ typedef JSONVar Var; class Callback { private: // Create a private variable - void (*_c)(Var); - void (*_cWStr)(Var, const char*); + void * _c; + + // To store type of the callback + int _type = 0; + + // Type to string + std::string mapType(int type) { + // Match type and return string + switch(type) { + // Handle cases + case 0: return "null"; + case 1: return "object"; + case 2: return "object"; + case 3: return "boolean"; + case 4: return "int"; + case 5: return "long"; + case 6: return "double"; + case 7: return "string"; + } + } + + // Function to generate an error + void error(int type) { + // Throw error + Serial.printf("[CASTING-ERROR] Was expecting %s and received %s\n", mapType(_type).c_str(), mapType(type).c_str()); + } public: // Default constructor will init the pointer Callback() { // We will init the context _c = NULL; - _cWStr = NULL; + + // Set type to null + _type = 0; } Callback(int ptr) { // We will init the context _c = NULL; - _cWStr = NULL; + + // Set type to null + _type = 0; } // For json callback Callback(void (*c)(Var)) { // We will store it in context - _c = c; + _c = (void *) c; + + // Set type to object + _type = 1; } Callback(void (*c)(Var, const char*)) { // We will store it in context - _cWStr = c; + _c = (void *) c; + + // Set type to object & str + _type = 2; + } + + Callback(void (*c)(bool, const char*)) { + // We will store it in context + _c = (void *) c; + + // Set type to bool & str + _type = 3; + } + + Callback(void (*c)(int, const char*)) { + // We will store it in context + _c = (void *) c; + + // Set type to int & str + _type = 4; + } + + Callback(void (*c)(long, const char*)) { + // We will store it in context + _c = (void *) c; + + // Set type to long & str + _type = 5; + } + + Callback(void (*c)(double, const char*)) { + // We will store it in context + _c = (void *) c; + + // Set type to double & str + _type = 6; + } + + Callback(void (*c)(const char*, const char*)) { + // We will store it in context + _c = (void *) c; + + // Set type to str & str + _type = 7; + } + + // Function to return type of callback + std::string type() { + // Map type and return + return mapType(_type); } // Then we will override the function call // operator to pass data to callback that we stored // in the context void operator()(Var data) { - // Transfer data callback - _c(data); + // Validate type + if (_type == 1) + // Cast as var function pointer only when function was accepting var + ((void (*)(Var)) _c)(data); + + else + // Invalid type + error(1); } // Overload for with string void operator()(Var data, const char* path) { - // Transfer data callback with string - _cWStr(data, path); + // Validate type + if (_type == 2) + // Cast as var function pointer only when function was accepting var + ((void (*)(Var, const char*)) _c)(data, path); + + else + // Invalid type + error(2); + } + + void operator()(bool data, const char* path) { + // Validate type + if (_type == 3) + // Cast as bool function pointer only when function was accepting bool + ((void (*)(bool, const char*)) _c)(data, path); + + else + // Invalid type + error(3); + } + + void operator()(int data, const char* path) { + // Validate type + if (_type == 4) + // Cast as int function pointer only when function was accepting int + ((void (*)(int, const char*)) _c)(data, path); + + else + // Invalid type + error(4); + } + + void operator()(long data, const char* path) { + // Validate type + if (_type == 5) + // Cast as long function pointer only when function was accepting long + ((void (*)(long, const char*)) _c)(data, path); + + else + // Invalid type + error(5); + } + + void operator()(double data, const char* path) { + // Validate type + if (_type == 6) + // Cast as double function pointer only when function was accepting double + ((void (*)(double, const char*)) _c)(data, path); + + else + // Invalid type + error(6); + } + + void operator()(const char* data, const char* path) { + // Validate type + if (_type == 7) + // Cast as string function pointer only when function was accepting string + ((void (*)(const char*, const char*)) _c)(data, path); + + else + // Invalid type + error(7); } // Override bool operator not bool operator!() { // Return true if the callback is not set - if (!_c && !_cWStr) return true; + if (!_c && _type == 0) return true; else return false; } }; From a9e7dc518b6f35289d0a32ff30ec1eff76f6f97c Mon Sep 17 00:00:00 2001 From: moizhusnain Date: Sat, 30 Jan 2021 01:53:33 +0500 Subject: [PATCH 07/11] Now the sub queues every message It will help us in restoring all subs when required also added unsub, which automatically deletes subs from queue --- src/Data.cpp | 41 ++++++++++++++++- src/Data.h | 19 +++++++- src/DuplexHandler.cpp | 102 +++++++++++++++++++++++++++++++++--------- src/DuplexHandler.h | 5 ++- src/EventQueue.cpp | 2 +- src/EventTable.cpp | 4 +- src/EventTable.h | 4 +- 7 files changed, 147 insertions(+), 30 deletions(-) diff --git a/src/Data.cpp b/src/Data.cpp index c176c2c..e7b4bb8 100644 --- a/src/Data.cpp +++ b/src/Data.cpp @@ -10,6 +10,40 @@ #include "Data.h" +// Constructors +Event::Event(String deviceID, DuplexHandler duplexHandler, gID id, String path) { + _duplex = duplexHandler; + _deviceID = deviceID; + _id = id; + _path = path; +} + +Event::Event() {} + +void Event::clear() { + // Clear an event handler on path + // Create a new json object + Var jsonObject; + + // Create packet + char jsonString[PACKET_SIZE]; + + // Add device id + jsonObject["deviceID"] = _deviceID; + + // Add path + jsonObject["path"] = _path; + + // Add data + jsonObject["event"] = "data"; + + // Conver the object to string + JSON.stringify(jsonObject).toCharArray(jsonString, PACKET_SIZE); + + // Send + _duplex.unsubscribe(_id, jsonString); +} + // Constructors Data::Data(String deviceID, DuplexHandler duplexHandler) { _duplex = duplexHandler; @@ -63,7 +97,7 @@ void Data::set(const char* path, Var data, Callback callback) { _duplex.send("/device/data/set", jsonString, callback); } -void Data::on(const char* path, Callback callback) { +Event Data::on(const char* path, Callback callback) { // Place an event handler on path update // Create a new json object Var jsonObject; @@ -90,5 +124,8 @@ void Data::on(const char* path, Callback callback) { std::string event = "data/" + p; // Send - _duplex.subscribe(event.c_str(), jsonString, callback); + gID packetID = _duplex.subscribe(event.c_str(), jsonString, callback); + + // Return an event + return Event(_deviceID, _duplex, packetID, path); } \ No newline at end of file diff --git a/src/Data.h b/src/Data.h index 763826c..96c9c96 100644 --- a/src/Data.h +++ b/src/Data.h @@ -16,6 +16,23 @@ #ifndef DATA_H_ #define DATA_H_ +class Event { + // Class will help in clearing an event + private: + DuplexHandler _duplex; + String _deviceID; + gID _id; + String _path; + + public: + // Event constructor + Event(String deviceID, DuplexHandler duplexHandler, gID id, String path); + Event(); + + // Clear method + void clear(); +}; + class Data { // Class for handling device related functions private: @@ -32,7 +49,7 @@ class Data { void set(const char* path, Var data, Callback callback); // Sync event handlers - void on(const char* path, Callback callback); + Event on(const char* path, Callback callback); }; #endif \ No newline at end of file diff --git a/src/DuplexHandler.cpp b/src/DuplexHandler.cpp index 974eb91..9688ec8 100644 --- a/src/DuplexHandler.cpp +++ b/src/DuplexHandler.cpp @@ -96,7 +96,6 @@ void DuplexHandler::handle(EventID id, EventKey key, EventPayload payload, Callb // Saving callback to eventsTable _eventsTable.insert(key, id, callback); - // Serial.println("On handle"); // _eventsTable.print(); // _subscriptions.print(); @@ -115,7 +114,6 @@ void DuplexHandler::send(const char* task, const char* payload, Callback callbac if(_status != CONNECTED) { // Append the packet to queue _queue.push(packetID, task, payload, callback); - // Serial.println("Stack to queue"); // _queue.print(); return ; } @@ -125,7 +123,6 @@ void DuplexHandler::send(const char* task, const char* payload, Callback callbac // Saving callback to eventsTable _eventsTable.insert(task, packetID, callback); - // Serial.println("On send"); // _eventsTable.print(); // _subscriptions.print(); @@ -136,18 +133,83 @@ void DuplexHandler::send(const char* task, const char* payload, Callback callbac client.sendTXT(packet); } -void DuplexHandler::subscribe(const char* event, const char* payload, Callback updateHandler) { +void DuplexHandler::unsubscribe(gID id, const char* payload) { // Generate an id - gID eventID = micros(); + gID packetID = micros(); + + // Remove callback from subscriptions table + _subscriptions.remove(id); + // _eventsTable.print(); + // _subscriptions.print(); + + // Push unsub to queue + _queue.push(packetID, "/topic/unsubscribe", payload, NULL); + + // and remove subscription packet from queue + _queue.remove(id); + // _queue.print(); + + // Check connection status + if(_status != CONNECTED) { + // Don't proceed if we aren't + return ; + } + + // Create packet + char packet[PACKET_SIZE]; // Saving callback to eventsTable - _subscriptions.insert(event, eventID, updateHandler); - // Serial.println("On subscribe"); + _eventsTable.insert("/topic/unsubscribe", packetID, NULL); // _eventsTable.print(); // _subscriptions.print(); - // Saving callback in event table with key - send("/topic/subscribe", payload, NULL); + // Formatting the packet + snprintf(packet, PACKET_SIZE, "{\"header\": {\"id\": %lu, \"task\": \"%s\"}, \"payload\": %s}", packetID, "/topic/unsubscribe", payload); + + // Sending to server + client.sendTXT(packet); +} + +gID DuplexHandler::subscribe(const char* event, const char* payload, Callback updateHandler) { + // Generate an id + gID packetID = micros(); + + // Saving callback to subscriptions Table + _subscriptions.insert(event, packetID, updateHandler); + // _eventsTable.print(); + // _subscriptions.print(); + + // Append the packet to queue because in case of queue + // the packet will always be queue either we are connected + // or disconnected + // This is being done to handle case where we were connected + // the subscribed to some events and got disconnected + _queue.push(packetID, "/topic/subscribe", payload, NULL); + // _queue.print(); + + // Check connection status + if(_status != CONNECTED) { + // Don't proceed if we aren't + // but return packet id + return packetID; + } + + // Create packet + char packet[PACKET_SIZE]; + + // Saving callback to eventsTable + _eventsTable.insert("/topic/subscribe", packetID, NULL); + // _eventsTable.print(); + // _subscriptions.print(); + + // Formatting the packet + snprintf(packet, PACKET_SIZE, "{\"header\": {\"id\": %lu, \"task\": \"%s\"}, \"payload\": %s}", packetID, "/topic/subscribe", payload); + + // Sending to server + client.sendTXT(packet); + + // Return packet id + return packetID; } void DuplexHandler::ping() { @@ -240,24 +302,22 @@ void duplexEventHandler(WStype_t eventType, uint8_t* packet, size_t length) { } // Fetching event callback function from the events Table - Callback callback = DuplexHandler::_eventsTable.findAndRemove( - (const char*) messageObject["header"]["task"], - (gID) messageObject["header"]["id"] - ); - + Callback callback = DuplexHandler::_eventsTable.findAndRemove((gID) messageObject["header"]["id"]); - // Serial.println("On message"); // DuplexHandler::_eventsTable.print(); // DuplexHandler::_subscriptions.print(); - // If not found then simply return - if(!callback) return; - // Remove the packet if it was queued // because the ack has been received - DuplexHandler::_queue.remove((long) messageObject["header"]["id"]); - // Serial.println("On remove"); - // DuplexHandler::_queue.print(); + if (messageObject["header"]["task"] == "/topic/subscribe"); + else { + // but if it is not of subscribe type + DuplexHandler::_queue.remove((long) messageObject["header"]["id"]); + // DuplexHandler::_queue.print(); + } + + // If not found then simply return + if(!callback) return; // Or otherwise resolve the event return callback(messageObject["payload"]); diff --git a/src/DuplexHandler.h b/src/DuplexHandler.h index 38ffa80..c46d523 100644 --- a/src/DuplexHandler.h +++ b/src/DuplexHandler.h @@ -58,8 +58,11 @@ class DuplexHandler { // Function to send a generic duplex message. static void send(const char* task, const char* payload, Callback callback); + // Function to unsubscribe to a device topic. + void unsubscribe(gID id, const char* payload); + // Function to subscribe to a device topic. - void subscribe(const char* event, const char* payload, Callback updateHandler); + gID subscribe(const char* event, const char* payload, Callback updateHandler); // Function to schedule an event handler for connection with Grandeur void onConnectionEvent(void connectionEventHandler(bool)); diff --git a/src/EventQueue.cpp b/src/EventQueue.cpp index f17f184..f1a1de2 100644 --- a/src/EventQueue.cpp +++ b/src/EventQueue.cpp @@ -135,7 +135,7 @@ void EventQueue::print() { // While not the end while (p != NULL) { // Print the id - Serial.printf("%s\n", p->key.c_str()); + Serial.printf("%s %d\n", p->key.c_str(), p->id); p = p->next; } diff --git a/src/EventTable.cpp b/src/EventTable.cpp index 072a88d..b9b5d0c 100644 --- a/src/EventTable.cpp +++ b/src/EventTable.cpp @@ -71,7 +71,7 @@ int EventTable::insert(EventKey key, EventID id, EventData data) { return 0; } -int EventTable::remove(EventKey key, EventID id) { +int EventTable::remove(EventID id) { // Check if bucket is empty if(table == NULL) { // which means the entry does not exist @@ -118,7 +118,7 @@ int EventTable::remove(EventKey key, EventID id) { return 0; } -EventData EventTable::findAndRemove(EventKey key, EventID id) { +EventData EventTable::findAndRemove(EventID id) { // Check if bucket is empty if(table == NULL) { // which means the entry does not exist diff --git a/src/EventTable.h b/src/EventTable.h index 13d7c57..672a273 100644 --- a/src/EventTable.h +++ b/src/EventTable.h @@ -42,10 +42,10 @@ class EventTable { int insert(EventKey key, EventID id, EventData data); // Method to remove an entry from the table - int remove(EventKey key, EventID id); + int remove(EventID id); // Method to find and remove an entry from the hashtable - EventData findAndRemove(EventKey key, EventID id); + EventData findAndRemove(EventID id); // Method to send some data to all callbacks at a key int emit(EventKey key, Var packet, const char* path); From bae566d6a9097eee0e2cfdb35e8f5f3cc61811cd Mon Sep 17 00:00:00 2001 From: Muhammad Abdullah Date: Sat, 30 Jan 2021 18:22:59 +0500 Subject: [PATCH 08/11] Readme.md is being updated. --- README.md | 278 +++++------------- .../CrossListening-esp32.ino | 22 +- .../CrossListening-esp8266.ino | 22 +- .../DashListening-App-esp32.ino | 16 +- .../DashListening-App-esp8266.ino | 16 +- .../DashListening-Device-esp32.ino | 8 +- .../DashListening-Device-esp8266.ino | 8 +- .../Logging/Logging-esp32/Logging-esp32.ino | 6 +- .../Logging-esp8266/Logging-esp8266.ino | 6 +- .../Searching-esp32/Searching-esp32.ino | 6 +- .../Searching-esp8266/Searching-esp8266.ino | 4 +- src/grandeurtypes.h | 2 +- 12 files changed, 134 insertions(+), 260 deletions(-) diff --git a/README.md b/README.md index ed98719..5a8e309 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ To get a deeper understanding of the core concepts Grandeur is built upon, dive ### Inclusion -When you include `` in your sketch, a global object `grandeur` is defined right away which you can use to initialize the SDK's configurations. +When you include `` in your sketch, a global object `grandeur` is created right away which you can use to initialize the SDK's configurations. ```cpp #include @@ -109,7 +109,7 @@ When you include `` in your sketch, a global object `grandeur` is de ### Initialization -Initialization is as simple as calling `grandeur.init()` with your credentials (Device ID, Project's API Key and Device's Access Token). The SDK uses your API key to select your project, and device ID and access token to limit its scope to only your device's data. It then returns a `Project` object which exposes other subclasses like `Device` and `Datastore`, and you can go programming your device from there. +Initialization is as simple as calling `grandeur.init()` with your credentials (Project's API Key and Device's Access Token). The SDK uses your API key to select your project, and device ID and access token to limit its scope to only your device's data. It then returns a `Project` object which exposes other subclasses like `Device` and `Datastore`, and you can go programming your device from there. ```cpp #include @@ -118,7 +118,7 @@ Project myProject; void setup() { // You can initialize device configurations like this. - myProject = grandeur.init(YourDeviceID, YourDeviceToken); + myProject = grandeur.init(YourAPIKey, AuthToken); } void loop() {} @@ -161,7 +161,7 @@ void setup() { // This sets up the device WiFi. setupWiFi(); // You can initialize device configurations like this. - myProject = grandeur.init(YourApiKey, YourDeviceToken); + myProject = grandeur.init(YourApiKey, AuthToken); } void loop() { @@ -181,7 +181,7 @@ You can see this line in the previous subsection: `myProject.loop(WiFi.status() You can also listen on SDK's connection-related events. For example, to run some code when the device makes a successful connection to the cloud or when the device's connection to the cloud breaks, you can wrap that code in a `Callback` function and pass it to `Project`'s `onConnection()` function. -The `Callback` function is a special type of function that accepts a `JSONObject` as a parameter and returns `void`. Read more about `Callback` and `JSONObject` [here][jsonobject]. +The `Callback` function is a special type of function that accepts a `Var` as a parameter and returns `void`. Read more about `Callback` and `Var` [here][var]. Here's how you can handle the connection event: @@ -248,9 +248,9 @@ On Grandeur, we generally store the device data in two containers: **summary** t They are all **Async functions** because they communicate with Grandeur through internet. Communication through internet takes some time and we cannot wait, for example, for device's summary variables to arrive from Grandeur -- meanwhile blocking the rest of the device program. So, what we do is, we schedule a function to be called when the summary variables and resume with rest of the device program, forgetting that we ever called `getSummary()`. When the summary variables arrive, the SDK calls our scheduled function, giving us access to summary variables inside that function. -For now, there's only one type of function that the SDK's Async methods accept: `Callback` which accepts a `JSONObject` as argument and returns nothing aka. `void`. +For now, there's only one type of function that the SDK's Async methods accept: `Callback` which accepts a `Var` as argument and returns nothing aka. `void`. -Read more about **Async functions**, `Callback`, and `JSONObject` [here][the dexterity of arduino sdk]. +Read more about **Async functions**, `Callback`, and `Var` [here][the dexterity of arduino sdk]. Here's how we would get and set device's summary and parms: @@ -272,7 +272,7 @@ void setupWiFi(void) { Serial.printf("\nDevice is connecting to WiFi using SSID %s and Passphrase %s.\n", ssid.c_str(), passphrase.c_str()); } -void getSummaryCallback(JSONObject result) { +void getSummaryCallback(Var result) { // This function prints the variables stored in summary and sets the device pins. Serial.printf("Voltage: %s\n", (int) result["deviceSummary"]["voltage"]); Serial.printf("Current: %s\n", (int) result["deviceSummary"]["current"]); @@ -280,19 +280,19 @@ void getSummaryCallback(JSONObject result) { analogWrite(A1, (int) result["deviceSummary"]["current"]); } -void getParmsCallback(JSONObject result) { +void getParmsCallback(Var result) { // This function prints the variables stored in parms and sets device pins. Serial.printf("State: %s\n", (bool) result["deviceParms"]["state"]); digitalWrite(D0, (bool) result["deviceParms"]["state"]); } -void setSummaryCallback(JSONObject result) { +void setSummaryCallback(Var result) { // This function prints the updated values of the variables stored in summary. Serial.printf("Updated Voltage: %s\n", (int) result["update"]["voltage"]); Serial.printf("Updated Current: %s\n", (int) result["update"]["current"]); } -void setParmsCallback(JSONObject result) { +void setParmsCallback(Var result) { // This function prints the updated values of the variables stored in parms. Serial.printf("Updated State: %s\n", (bool) result["update"]["state"]); } @@ -314,12 +314,12 @@ void loop() { // Getting device's parms myDevice.getParms(getParmsCallback); // Updating device's summary - JSONObject summary; + Var summary; summary["voltage"] = analogRead(A0); summary["current"] = analogRead(A1); myDevice.setSummary(summary, setSummaryCallback); // Updating device's parms - JSONObject parms; + Var parms; parms["state"] = digitalRead(D0); myDevice.setParms(parms, setParmsCallback); } @@ -359,13 +359,13 @@ void setupWiFi(void) { Serial.printf("\nDevice is connecting to WiFi using SSID %s and Passphrase %s.\n", ssid.c_str(), passphrase.c_str()); } -void summaryUpdatedCallback(JSONObject result) { +void summaryUpdatedCallback(Var result) { // This function prints the updated values of the variables stored in summary. Serial.printf("Updated Voltage: %s\n", (int) updatedSummary["voltage"]); Serial.printf("Updated Current: %s\n", (int) updatedSummary["current"]); } -void parmsUpdatedCallback(JSONObject result) { +void parmsUpdatedCallback(Var result) { // This function prints the updated values of the variables stored in parms. Serial.printf("Updated State: %s\n", (int) updatedParms["state"]); } @@ -484,7 +484,7 @@ void setupWiFi(void) { Serial.printf("\nDevice is connecting to WiFi using SSID %s and Passphrase %s.\n", ssid.c_str(), passphrase.c_str()); } -void getParmsCallback(JSONObject parms) { +void getParmsCallback(Var parms) { if(payload["code"] == "DEVICE-PARMS-FETCHED") { bool state = (bool) payload["deviceParms"]["state"]; // You can set a digital pin here with the state value @@ -534,7 +534,7 @@ void setupWiFi(void) { Serial.printf("\nDevice is connecting to WiFi using SSID %s and Passphrase %s.\n", ssid.c_str(), passphrase.c_str()); } -void getParmsCallback(JSONObject parms) { +void getParmsCallback(Var parms) { if(payload["code"] == "DEVICE-PARMS-FETCHED") { bool state = (bool) payload["deviceParms"]["state"]; // You can set a digital pin here with the state value @@ -543,7 +543,7 @@ void getParmsCallback(JSONObject parms) { } } -void parmsUpdatedCallback(JSONObject parms) { +void parmsUpdatedCallback(Var parms) { bool newState = (bool) updatedParms["state"]; // You can set a digital pin here with the newState value // to switch the hardware connected to it ON/OFF. @@ -593,7 +593,7 @@ void setupWiFi(void) { Serial.printf("\nDevice is connecting to WiFi using SSID %s and Passphrase %s.\n", ssid.c_str(), passphrase.c_str()); } -void getParmsCallback(JSONObject parms) { +void getParmsCallback(Var parms) { if(payload["code"] == "DEVICE-PARMS-FETCHED") { bool state = (bool) payload["deviceParms"]["state"]; // You can set a digital pin here with the state value @@ -602,14 +602,14 @@ void getParmsCallback(JSONObject parms) { } } -void parmsUpdatedCallback(JSONObject parms) { +void parmsUpdatedCallback(Var parms) { bool newState = (bool) updatedParms["state"]; // You can set a digital pin here with the newState value // to switch the hardware connected to it ON/OFF. digitalWrite(D0, newState); } -void setParmsCallback(JSONObject parms) { +void setParmsCallback(Var parms) { if(result["code"] == "DEVICE-PARMS-UPDATED") { Serial.printf("State is updated to: %d\n", (bool) payload["update"]["state"]); } @@ -632,7 +632,7 @@ void setup() { void loop() { // Parms container to store device's state. - JSONObject parms; + Var parms; parms["state"] = digitalRead(D0); // This sends the updated parms to Grandeur and calls setParmsCallback() when // the response from the cloud arrives. @@ -668,21 +668,21 @@ The Arduino SDK is aimed at providing extremely to-the-point functions, being al * `onParmsUpdated(Callback callback)` * `getSummary(Callback callback)` * `getParms(Callback callback)` - * `setSummary(JSONObject summary, Callback callback)` - * `setParms(JSONObject parms, Callback callback)` + * `setSummary(Var summary, Callback callback)` + * `setParms(Var parms, Callback callback)` `getParms()` for example, requests the cloud for the device's parms and schedules the `callback` function for when the parms arrive, because obviously, they don't arrive instantaneously; there is always some latency involved in web communications. * There is a special type of function defined in **Arduino SDK** as [`Callback`][callback]. It's nothing but a regular function of the form: ```cpp - void callback(JSONObject result) {} + void callback(Var result) {} ``` For now, it is the only function type that the Async functions of SDK accept as argument. -* [`JSONObject`][jsonobject] is a special variable type which acts like a container for other variables, just like a javascript object or a C++ map. You can store variables in it as key-value pairs. This what summary and parms are -- container for other variables aka. `JSONObject`s. +* [`Var`][var] is a special variable type which acts like a container for other variables, just like a javascript object or a C++ map. You can store variables in it as key-value pairs. This what summary and parms are -- container for other variables aka. `Var`s. ```cpp -JSONObject summary; +Var summary; summary["foo"] = "This is foo"; summary["bar"] = true; summary["foobar"]["foo"] = "This is foo inside foobar"; @@ -819,17 +819,17 @@ So to allow a web app to interact with your project using the Web SDK, you first # Documentation -`Project` is the main class and all functionalities originate from it. You get the object of this class when you initialize SDK's configurations using `grandeur.init()`. You can safely imagine the object of `Project` class as a reference to your project on Grandeur. +`Project` is the main class and all functionalities originate from it. You can safely imagine the object of `Project` class as a reference to your project on Grandeur. You get a reference to this object when you initialize SDK's configurations using `grandeur.init()`. `grandeur` is the global object that gets available right away when you include `` in your sketch. It has just one purpose and therefore gives you only one function: `grandeur.init()`. -> ***Note 2***: You cannot connect with Grandeur or even with internet without first connecting with the WiFi. Therefore, the examples below are just for reference and you are required to handle your device's WiFi in order for them to work. You can see [these examples][Examples] to get a deeper understanding. They show WiFi handling too. 😉 +> ***Note 2***: You cannot connect with Grandeur or even with internet without first connecting with the WiFi. Therefore, the examples below are just for reference and you are required to handle your device's WiFi in order for things to work. You can see [these examples][Examples] to get a deeper understanding. They do WiFi handling too. 😉 ### init -> grandeur.init (deviceID: _String_, apiKey: _String_, token: _String_) : returns _Project_ +> grandeur.init (apiKey: _String_, token: _String_) : returns _Project_ -This method initializes SDK's connection configurations: `apiKey` and `authToken`, and returns an object of the `Project` class. `Project` class is the main class that exposes all functions of the SDK. +This method initializes SDK's connection configurations: `apiKey` and `authToken`, and returns a reference to object of the `Project` class. `Project` class is the main class that exposes all functions of the SDK. #### Parameters @@ -854,7 +854,7 @@ void setup() { ## Project -Project is the main class of the SDK. When SDK connects with Grandeur, this class represents your cloud project. But Arduino SDK's functionality is limited to devices and datastore APIs which are wrapped by their respective classes. +Project is the main class of the SDK. When SDK connects with Grandeur, this class represents your cloud project, tuned down to the device scope. There are only two APIs you can interact with: device and datastore, which are represented by their respective classes. This class exposes the following methods: @@ -899,7 +899,7 @@ This method schedules a function to be called when the SDK's connection with Gra | Name | Type | Description | |-------------|------------------|--------------------------------------------------------------------------------| -| callback | _void (*)(bool)_ | An event handler function for device's connection/disconnection with Grandeur | +| callback | _void (*)(bool)_ | An event handler function for device's connection/disconnection with Grandeur | #### Example @@ -964,7 +964,7 @@ void loop() { > device (deviceID: _String_) : returns _Device_ -This method returns an object of the **Device** class. Read about **Device** class [here][Device Class]. +This method returns a reference to object of the **Device** class. Read about **Device** class [here][Device Class]. #### Example @@ -984,7 +984,7 @@ void setup() { > datastore (void) : returns _Datastore_ -This method returns an object of the **Datastore** class. Datastore class exposes the functions of the datastore API which handles your queries to your project's datastore like: logging device variables to the cloud datastore, searching for data, etc. +This method returns a reference to object of the **Datastore** class. Datastore class exposes the functions of the datastore API which handles your queries to your project's datastore like: logging device variables to the cloud datastore, searching for data, etc. #### Example @@ -1002,21 +1002,22 @@ void setup() { ## Device -Device class exposes the functions of the device API. It generally handles your device's data on Grandeur like: updating device variables on Grandeur, pulling variables from Grandeur, listening for cloud updates in your device variables, and so on. +Device class exposes the functions of the device API. Its data function returns a reference to object of `Data` class which represents device's data space. You can use it to update device variables on Grandeur, pulling variables from Grandeur, listening for updates in your device variables, etc. -It exposes the following functions: +Device's `Data` class exposes the following functions: -### getSummary +### get -> getSummary (callback: _Callback_) : returns _void_ +> get (path: _String_, callback: _Callback_) : returns _void_ -This method gets device's [summary][summary] from Grandeur. +This method gets a device variable from Grandeur. #### Parameters | Name | Type | Description | |-------------|------------|--------------------------------------------------------------| -| callback | _Callback_ | A function to be called when getSummary response is received | +| path | _String_ | Path of the device variable using dot notation | +| callback | _Callback_ | A function to be called when get response is received | #### Example @@ -1024,9 +1025,9 @@ This method gets device's [summary][summary] from Grandeur. Project myProject; Device myDevice; -void getSummaryCallback(JSONObject result) { +void getVoltageCallback(Var result) { // This method just prints *voltage* variable from the device's summary. - Serial.println(result["summary"]["voltage"]<<"\n"); + Serial.println(result["data"]<<"\n"); } void setup() { @@ -1037,67 +1038,28 @@ void setup() { void loop() { // This gets the summary on every loop and calls getSummaryCallback() function when its // response from the cloud is received. - myDevice.getSummary(getSummaryCallback); + myDevice.data().get("voltage", getVoltageCallback); myProject.loop(true); } // **RESULT** -// Prints the value of the voltage variable stored in the device's summary on every loop. +// Prints the value of the voltage variable from Grandeur on every loop. ``` -### getParms +### set -> getParms (callback: _Callback_) : returns _void_ +> set (path : _String_, data : _any_, callback: _Callback_) : returns _void_ -This method gets device's [parms][parms] from Grandeur. - -#### Parameters - -| Name | Type | Description | -|-------------|------------|------------------------------------------------------------| -| callback | _Callback_ | A function to be called when getParms response is received | - -#### Example - -```cpp -Project myProject; -Device myDevice; - -void getParmsCallback(JSONObject result) { - // This method just prints *state* variable from the device's parms. - Serial.println(result["parms"]["state"]<<"\n"); -} - -void setup() { - myProject = grandeur.init(YourApiKey, YourToken); - myDevice = myProject.device(YourDeviceID); -} - -void loop() { - // This gets the parms on every loop and calls getParmsCallback() function when its - // response from the cloud is received. - myDevice.getParms(getParmsCallback); - - myProject.loop(true); -} - -// **RESULT** -// Prints the value of the state variable stored in the device's parms on every loop. -``` - -### setSummary - -> setSummary (summary : _JSONObject_, callback: _Callback_) : returns _void_ - -This method updates the device's [summary][summary] on Grandeur with new values. +This method updates a device variable on Grandeur with new data. #### Parameters | Name | Type | Description | |-------------|---------------|--------------------------------------------------------------| -| summary | _JSONObject_ | A JSONObject containing the summary variables | -| callback | _Callback_ | A function to be called when setSummary response is received | +| path | _String_ | Path of the device variable using dot notation | +| data | _Var_ | New data to store in the variable | +| callback | _Callback_ | A function to be called when set response is received | #### Example @@ -1105,10 +1067,9 @@ This method updates the device's [summary][summary] on Grandeur with new values. Project myProject; Device myDevice; -void setSummaryCallback(JSONObject result) { - // This method prints *voltage* and *current* variables from device's updated summary. - Serial.println(result["update"]["voltage"]<<"\n"); - Serial.println(result["update"]["current"]<<"\n"); +void setVoltageCallback(Var result) { + // This method prints *voltage* value after it is updated on Grandeur. + Serial.println(result["update"]); } void setup() { @@ -1117,13 +1078,11 @@ void setup() { } void loop() { - // A JSONObject container to store summary variables. - JSONObject summary; - summary["voltage"] = analogRead(A0); - summary["current"] = analogRead(A1); + // Reading pin value. + int voltage = analogRead(A0); // This sets the summary on every loop and calls setSummaryCallback() function when its // response from the cloud is received. - myDevice.setSummary(summary, setSummaryCallback); + myDevice.data().set("voltage", voltage, setVoltageCallback); myProject.loop(true); } @@ -1133,64 +1092,20 @@ void loop() { // variables (voltage and current in our case) on every loop. ``` -### setParms - -> setParms (parms : _JSONObject_, callback: _Callback_) : returns _void_ - -Setter method for device's [parms][parms]. - -#### Parameters - -| Name | Type | Description | -|-------------|--------------|-----------------------------------------------------------------| -| parms | _JSONObject_ | A JSONObject containing the summary variables | -| callback | _Callback_ | A function to be called when setParms response is received | - -#### Example - -```cpp -Project myProject; -Device myDevice; - -void setParmsCallback(JSONObject result) { - // This method prints *state* variable from device's updated parms. - Serial.println(result["parms"]["state"]<<"\n"); -} - -void setup() { - myProject = grandeur.init(YourApiKey, YourToken); - myDevice = myProject.device(YourDeviceID); -} - -void loop() { - // A JSONObject container to store parms variables. - JSONObject parms; - parms["state"] = digitalRead(D0); - // This sets the parms on every loop and calls setParmsCallback() function when its - // response from the cloud is received. - myDevice.setParms(parms, setParmsCallback); - - myProject.loop(true); -} - -// **RESULT** -// Setts the parms and prints the updated values of the parms -// variables (just state in our case) on every loop -``` - -### onSummary +### on -> onSummary (callback : _Callback_) : returns _void_ +> on (path: _String_, callback : _Callback_) : returns _void_ -This method schedules a function to be called when the summary of the device is updated on Grandeur. +This method schedules a function to be called when a device variable changes on Grandeur. > ***A Tidbit***: *Update is a special type of event* and the function that handles it is called an **update handler**. #### Parameters -| Name | Type | Description | -|-------------|------------|----------------------------------------| -| callback | _Callback_ | An update handler for device's summary | +| Name | Type | Description | +|-------------|------------|------------------------------------------------| +| path | _String_ | Path of the device variable using dot notation | +| callback | _Callback_ | An update handler for the device variable | More on Callback [here][callback]. @@ -1200,60 +1115,19 @@ More on Callback [here][callback]. Project myProject; Device myDevice; -void summaryUpdatedCallback(JSONObject result) { +void voltageUpdatedCallback(Var result) { // When summary update occurs on Grandeur, this function extracts the updated values of // voltage and current, and sets the corresponding pins. Serial.println("Summary update occurred!\n"); int voltage = updatedSummary["voltage"]; - int current = updatedSummary["current"]; digitalWrite(voltage, A0); - digitalWrite(current, A1); } void setup() { myProject = grandeur.init(YourApiKey, YourToken); myDevice = myProject.device(YourDeviceID); - myDevice.onSummary(summaryUpdatedCallback); -} - -void loop() { - myProject.loop(true); -} -``` - -### onParms - -> onParms (callback : _Callback_) : returns _void_ - -This method schedules a function to be called when the parms of the device are updated on Grandeur. - -#### Parameters - -| Name | Type | Description | -|-------------|------------|--------------------------------------| -| callback | _Callback_ | An update handler for device's parms | - -More on Callback [here][callback]. - -#### Example - -```cpp -Project myProject; -Device myDevice; - -void parmsUpdatedCallback(JSONObject updatedParms) { - // When parms update occurs on Grandeur, this function extracts the updated value of - // state, and sets the corresponding pin. - Serial.println("Parms update occurred!\n"); - int state = updatedParms["state"]; - digitalWrite(D0, state); -} - -void setup() { - myProject = grandeur.init(YourApiKey, YourToken); - myDevice = myProject.device(YourDeviceID); - myDevice.onParms(parmsUpdatedCallback); + myDevice.on("voltage", voltageUpdatedCallback); } void loop() { @@ -1269,7 +1143,7 @@ It exposes the following functions: ### insert -> insert (documents: _JSONObject_, callback: _Callback_) : returns _void_ +> insert (documents: _Var_, callback: _Callback_) : returns _void_ This method inserts documents into Grandeur datastore. @@ -1277,7 +1151,7 @@ This method inserts documents into Grandeur datastore. | Name | Type | Description | |-------------|--------------|--------------------------------------------------------------------------| -| documents | _JSONObject_ | An array of documents (_JSONObject_ s) to be inserted into the datastore | +| documents | _Var_ | An array of documents (_Var_ s) to be inserted into the datastore | | callback | _Callback_ | A function to be called when insertion of documents is completed | #### Example @@ -1286,7 +1160,7 @@ This method inserts documents into Grandeur datastore. Project myProject; Datastore myDatastore; -void insertCallback(JSONObject insertionResult) { +void insertCallback(Var insertionResult) { // This method just prints if the insertion is successful or not. if(insertionResult["code"] == "DATASTORE-DOCUMENTS-INSERTED") { Serial.println("Insertion successful."); @@ -1301,7 +1175,7 @@ void setup() { void loop() { // This inserts a document containing voltage and current readings in datastore on every loop. - JSONObject docs; + Var docs; // Adding voltage and current readings to the first document of docs array. // In JSON, the docs array looks like this: // [{"voltage": analogRead(A0), "current": analogRead(A1)}] @@ -1321,7 +1195,7 @@ void loop() { ### search -> search (filter: _JSONObject_, projection: _JSONObject_, pageNumber: _int_, callback: _Callback_) : returns _void_ +> search (filter: _Var_, projection: _Var_, pageNumber: _int_, callback: _Callback_) : returns _void_ This method searches for documents in Grandeur datastore based on the `filter` supplied. `Filter` describes what documents to return and `projection` describes what fields to mask/unmask in those documents. Their is a limit on the how many documents can be returned in one query. The documents are divided into pages and you can get subsequent pages by specifying the `pageNumber`. @@ -1329,8 +1203,8 @@ This method searches for documents in Grandeur datastore based on the `filter` s | Name | Type | Description | |-------------|--------------|--------------------------------------------------------------------------------------------| -| filter | _JSONObject_ | A document that describes the conditions which the documents should satisfy to be returned | -| projection | _JSONObject_ | A document that describes what fields to return | +| filter | _Var_ | A document that describes the conditions which the documents should satisfy to be returned | +| projection | _Var_ | A document that describes what fields to return | | pageNumber | _int_ | Number of the requested page | | callback | _Callback_ | A function to be called when insertion of documents is completed | @@ -1340,7 +1214,7 @@ This method searches for documents in Grandeur datastore based on the `filter` s Project myProject; Datastore myDatastore; -void searchCallback(JSONObject searchResult) { +void searchCallback(Var searchResult) { // This method just prints the documents if the search is successful. if(searchResult["code"] == "DATASTORE-DOCUMENTS-FETCHED") { Serial.print("Documents fetched from Grandeur: "); @@ -1415,7 +1289,7 @@ Here are some enhancements that we are considering to implement in the SDK. They [summary]: #device-registry "Summary" [parms]: #device-registry "Parms" [callback]: #the-dexterity-of-arduino-sdk "The Dexterity of Arduino SDK" -[jsonobject]: #the-dexterity-of-arduino-sdk "The Dexterity of Arduino SDK" +[var]: #the-dexterity-of-arduino-sdk "The Dexterity of Arduino SDK" [the dexterity of arduino sdk]: #the-dexterity-of-arduino-sdk "The Dexterity of Arduino SDK" [models]: #models "Models" [apikey]: #project "Project" diff --git a/examples/CrossListening/CrossListening-esp32/CrossListening-esp32.ino b/examples/CrossListening/CrossListening-esp32/CrossListening-esp32.ino index 6d3b4be..16d25a7 100644 --- a/examples/CrossListening/CrossListening-esp32/CrossListening-esp32.ino +++ b/examples/CrossListening/CrossListening-esp32/CrossListening-esp32.ino @@ -39,11 +39,11 @@ int voltagePin = 2; // Function prototypes void WiFiEventCallback(WiFiEvent_t event); void setupWiFi(void); -void connectionCallback(JSONObject updateObject); -void initializeState(JSONObject getResult); -void parmsUpdatedCallback(JSONObject updatedParms); -void summarySetCallback(JSONObject setResult); -void parmsSetCallback(JSONObject setResult); +void connectionCallback(Var updateObject); +void initializeState(Var getResult); +void parmsUpdatedCallback(Var updatedParms); +void summarySetCallback(Var setResult); +void parmsSetCallback(Var setResult); void setup() { @@ -71,14 +71,14 @@ void loop() { // every five seconds. Serial.println("Setting Summary"); - JSONObject summary; + Var summary; summary["voltage"] = analogRead(voltagePin); // This updates the summary of our device on Grandeur and schedules summarySetCallback() // function to be called when Grandeur responds with the SUMMARY UPDATED message. myDevice.setSummary(summary, summarySetCallback); Serial.println("Setting Parms"); - JSONObject parms; + Var parms; parms["state"] = digitalRead(statePin); // This updates the parms of our device on Grandeur and schedules parmsSetCallback() // function to be called when Grandeur responds with the PARMS UPDATED message. @@ -140,7 +140,7 @@ void connectionCallback(bool state) { } } -void initializeState(JSONObject getResult) { +void initializeState(Var getResult) { // This function sets the *state pin* to the *state value* that we received in parms // from the cloud. if(getResult["code"] == "DEVICE-PARMS-FETCHED") { @@ -153,14 +153,14 @@ void initializeState(JSONObject getResult) { return; } -void parmsUpdatedCallback(JSONObject updatedParms) { +void parmsUpdatedCallback(Var updatedParms) { // This function gets the *updated state* from the device parms and set the *state pin* // with *state value*. Serial.printf("Updated State is: %d\n", (bool) updatedParms["state"]); digitalWrite(statePin, (bool) updatedParms["state"]); } -void summarySetCallback(JSONObject setResult) { +void summarySetCallback(Var setResult) { if(setResult["code"] == "DEVICE-SUMMARY-UPDATED") { Serial.printf("Voltage is updated to: %d\n", (int) setResult["update"]["voltage"]); @@ -174,7 +174,7 @@ void summarySetCallback(JSONObject setResult) { return; } -void parmsSetCallback(JSONObject setResult) { +void parmsSetCallback(Var setResult) { if(setResult["code"] == "DEVICE-PARMS-UPDATED") { Serial.printf("State is updated to: %d\n", (bool) setResult["update"]["state"]); diff --git a/examples/CrossListening/CrossListening-esp8266/CrossListening-esp8266.ino b/examples/CrossListening/CrossListening-esp8266/CrossListening-esp8266.ino index a02c65f..7503b66 100644 --- a/examples/CrossListening/CrossListening-esp8266/CrossListening-esp8266.ino +++ b/examples/CrossListening/CrossListening-esp8266/CrossListening-esp8266.ino @@ -40,11 +40,11 @@ int voltagePin = A0; // Function prototypes void setupWiFi(void); -void connectionCallback(JSONObject updateObject); -void initializeState(JSONObject getResult); -void parmsUpdatedCallback(JSONObject updatedParms); -void summarySetCallback(JSONObject setResult); -void parmsSetCallback(JSONObject setResult); +void connectionCallback(Var updateObject); +void initializeState(Var getResult); +void parmsUpdatedCallback(Var updatedParms); +void summarySetCallback(Var setResult); +void parmsSetCallback(Var setResult); void setup() { @@ -72,14 +72,14 @@ void loop() { // every five seconds. Serial.println("Setting Summary"); - JSONObject summary; + Var summary; summary["voltage"] = analogRead(voltagePin); // This updates the summary of our device on Grandeur and schedules summarySetCallback() // function to be called when Grandeur responds with the SUMMARY UPDATED message. myDevice.setSummary(summary, summarySetCallback); Serial.println("Setting Parms"); - JSONObject parms; + Var parms; parms["state"] = digitalRead(statePin); // This updates the parms of our device on Grandeur and schedules parmsSetCallback() // function to be called when Grandeur responds with the PARMS UPDATED message. @@ -134,7 +134,7 @@ void connectionCallback(bool state) { } } -void initializeState(JSONObject getResult) { +void initializeState(Var getResult) { // This function sets the *state pin* to the *state value* that we received in parms // from the cloud. if(getResult["code"] == "DEVICE-PARMS-FETCHED") { @@ -147,14 +147,14 @@ void initializeState(JSONObject getResult) { return; } -void parmsUpdatedCallback(JSONObject updatedParms) { +void parmsUpdatedCallback(Var updatedParms) { // This function gets the *updated state* from the device parms and set the *state pin* // with *state value*. Serial.printf("Updated State is: %d\n", (bool) updatedParms["state"]); digitalWrite(statePin, (bool) updatedParms["state"]); } -void summarySetCallback(JSONObject setResult) { +void summarySetCallback(Var setResult) { if(setResult["code"] == "DEVICE-SUMMARY-UPDATED") { Serial.printf("Voltage is updated to: %d\n", (int) setResult["update"]["voltage"]); @@ -168,7 +168,7 @@ void summarySetCallback(JSONObject setResult) { return; } -void parmsSetCallback(JSONObject setResult) { +void parmsSetCallback(Var setResult) { if(setResult["code"] == "DEVICE-PARMS-UPDATED") { Serial.printf("State is updated to: %d\n", (bool) setResult["update"]["state"]); diff --git a/examples/DashListening-App/DashListening-App-esp32/DashListening-App-esp32.ino b/examples/DashListening-App/DashListening-App-esp32/DashListening-App-esp32.ino index 4a71534..8fd9ed5 100644 --- a/examples/DashListening-App/DashListening-App-esp32/DashListening-App-esp32.ino +++ b/examples/DashListening-App/DashListening-App-esp32/DashListening-App-esp32.ino @@ -36,9 +36,9 @@ int voltagePin = 2; void WiFiEventCallback(WiFiEvent_t event); void setupWiFi(void); void connectionCallback(bool state); -void initializeState(JSONObject getResult); -void summarySetCallback(JSONObject setResult); -void parmsSetCallback(JSONObject setResult); +void initializeState(Var getResult); +void summarySetCallback(Var setResult); +void parmsSetCallback(Var setResult); void setup() { Serial.begin(9600); @@ -62,14 +62,14 @@ void loop() { // every five seconds. Serial.println("Setting Summary"); - JSONObject summary; + Var summary; summary["voltage"] = analogRead(voltagePin); // This updates the summary of our device on Grandeur and schedules summarySetCallback() // function to be called when Grandeur responds with the SUMMARY UPDATED message. myDevice.setSummary(summary, summarySetCallback); Serial.println("Setting Parms"); - JSONObject parms; + Var parms; parms["state"] = digitalRead(statePin); // This updates the parms of our device on Grandeur and schedules parmsSetCallback() // function to be called when Grandeur responds with the PARMS UPDATED message. @@ -130,7 +130,7 @@ void connectionCallback(bool state) { } } -void initializeState(JSONObject getResult) { +void initializeState(Var getResult) { // This function sets the *state pin* to the *state value* that we received in parms // from the cloud. if(getResult["code"] == "DEVICE-PARMS-FETCHED") { @@ -143,7 +143,7 @@ void initializeState(JSONObject getResult) { return; } -void summarySetCallback(JSONObject setResult) { +void summarySetCallback(Var setResult) { if(setResult["code"] == "DEVICE-SUMMARY-UPDATED") { Serial.printf("Voltage is updated to: %d\n", (int) setResult["update"]["voltage"]); @@ -157,7 +157,7 @@ void summarySetCallback(JSONObject setResult) { return; } -void parmsSetCallback(JSONObject setResult) { +void parmsSetCallback(Var setResult) { if(setResult["code"] == "DEVICE-PARMS-UPDATED") { Serial.printf("State is updated to: %d\n", (bool) setResult["update"]["state"]); diff --git a/examples/DashListening-App/DashListening-App-esp8266/DashListening-App-esp8266.ino b/examples/DashListening-App/DashListening-App-esp8266/DashListening-App-esp8266.ino index 0998efb..55984d7 100644 --- a/examples/DashListening-App/DashListening-App-esp8266/DashListening-App-esp8266.ino +++ b/examples/DashListening-App/DashListening-App-esp8266/DashListening-App-esp8266.ino @@ -37,9 +37,9 @@ int voltagePin = A0; // Function prototypes void setupWiFi(void); void connectionCallback(bool state); -void initializeState(JSONObject getResult); -void summarySetCallback(JSONObject setResult); -void parmsSetCallback(JSONObject setResult); +void initializeState(Var getResult); +void summarySetCallback(Var setResult); +void parmsSetCallback(Var setResult); void setup() { Serial.begin(9600); @@ -63,14 +63,14 @@ void loop() { // every five seconds. Serial.println("Setting Summary"); - JSONObject summary; + Var summary; summary["voltage"] = analogRead(voltagePin); // This updates the summary of our device on Grandeur and schedules summarySetCallback() // function to be called when Grandeur responds with the SUMMARY UPDATED message. myDevice.setSummary(summary, summarySetCallback); Serial.println("Setting Parms"); - JSONObject parms; + Var parms; parms["state"] = digitalRead(statePin); // This updates the parms of our device on Grandeur and schedules parmsSetCallback() // function to be called when Grandeur responds with the PARMS UPDATED message. @@ -124,7 +124,7 @@ void connectionCallback(bool state) { } } -void initializeState(JSONObject getResult) { +void initializeState(Var getResult) { // This function sets the *state pin* to the *state value* that we received in parms // from the cloud. if(getResult["code"] == "DEVICE-PARMS-FETCHED") { @@ -137,7 +137,7 @@ void initializeState(JSONObject getResult) { return; } -void summarySetCallback(JSONObject setResult) { +void summarySetCallback(Var setResult) { if(setResult["code"] == "DEVICE-SUMMARY-UPDATED") { Serial.printf("Voltage is updated to: %d\n", (int) setResult["update"]["voltage"]); @@ -151,7 +151,7 @@ void summarySetCallback(JSONObject setResult) { return; } -void parmsSetCallback(JSONObject setResult) { +void parmsSetCallback(Var setResult) { if(setResult["code"] == "DEVICE-PARMS-UPDATED") { Serial.printf("State is updated to: %d\n", (bool) setResult["update"]["state"]); diff --git a/examples/DashListening-Device/DashListening-Device-esp32/DashListening-Device-esp32.ino b/examples/DashListening-Device/DashListening-Device-esp32/DashListening-Device-esp32.ino index bc12bde..7454fd1 100644 --- a/examples/DashListening-Device/DashListening-Device-esp32/DashListening-Device-esp32.ino +++ b/examples/DashListening-Device/DashListening-Device-esp32/DashListening-Device-esp32.ino @@ -34,8 +34,8 @@ int statePin = 4; void WiFiEventCallback(WiFiEvent_t event); void setupWiFi(void); void connectionCallback(bool state); -void initializeState(JSONObject getResult); -void parmsUpdatedCallback(JSONObject updatedParms); +void initializeState(Var getResult); +void parmsUpdatedCallback(Var updatedParms); void setup() { Serial.begin(9600); @@ -101,7 +101,7 @@ void connectionCallback(bool status) { } } -void initializeState(JSONObject getResult) { +void initializeState(Var getResult) { // This function sets the *state pin* to the *state value* that we received in parms // from the cloud. if(getResult["code"] == "DEVICE-PARMS-FETCHED") { @@ -114,7 +114,7 @@ void initializeState(JSONObject getResult) { return; } -void parmsUpdatedCallback(JSONObject updatedParms) { +void parmsUpdatedCallback(Var updatedParms) { // This function gets the *updated state* from the device parms and set the *state pin* // with *state value*. Serial.printf("Updated State is: %d\n", (bool) updatedParms["state"]); diff --git a/examples/DashListening-Device/DashListening-Device-esp8266/DashListening-Device-esp8266.ino b/examples/DashListening-Device/DashListening-Device-esp8266/DashListening-Device-esp8266.ino index d95a63c..47a59ad 100644 --- a/examples/DashListening-Device/DashListening-Device-esp8266/DashListening-Device-esp8266.ino +++ b/examples/DashListening-Device/DashListening-Device-esp8266/DashListening-Device-esp8266.ino @@ -35,8 +35,8 @@ int statePin = D0; // Function prototypes void setupWiFi(void); void connectionCallback(bool state); -void initializeState(JSONObject getResult); -void parmsUpdatedCallback(JSONObject updatedParms); +void initializeState(Var getResult); +void parmsUpdatedCallback(Var updatedParms); void setup() { Serial.begin(9600); @@ -95,7 +95,7 @@ void connectionCallback(bool status) { } } -void initializeState(JSONObject getResult) { +void initializeState(Var getResult) { // This function sets the *state pin* to the *state value* that we received in parms // from the cloud. if(getResult["code"] == "DEVICE-PARMS-FETCHED") { @@ -108,7 +108,7 @@ void initializeState(JSONObject getResult) { return; } -void parmsUpdatedCallback(JSONObject updatedParms) { +void parmsUpdatedCallback(Var updatedParms) { // This function gets the *updated state* from the device parms and set the *state pin* // with *state value*. Serial.printf("Updated State is: %d\n", (bool) updatedParms["state"]); diff --git a/examples/Datastore/Logging/Logging-esp32/Logging-esp32.ino b/examples/Datastore/Logging/Logging-esp32/Logging-esp32.ino index d40552a..f57dfd5 100644 --- a/examples/Datastore/Logging/Logging-esp32/Logging-esp32.ino +++ b/examples/Datastore/Logging/Logging-esp32/Logging-esp32.ino @@ -32,7 +32,7 @@ unsigned long current = millis(); void WiFiEventCallback(WiFiEvent_t event); void setupWiFi(void); void connectionCallback(bool status); -void insertCallback(JSONObject payload); +void insertCallback(Var payload); void setup() { Serial.begin(9600); @@ -52,7 +52,7 @@ void loop() { if(millis() - current >= 5000) { // This if-condition makes sure that the code inside this block runs only after // every five seconds. - JSONObject logs; + Var logs; logs[0]["voltage"] = analogRead(A0); myDatastore.collection("logs").insert(logs, insertCallback); // This updates the millis counter for @@ -107,7 +107,7 @@ void connectionCallback(bool status) { } } -void insertCallback(JSONObject insertResult) { +void insertCallback(Var insertResult) { // This function prints if the logs were successfully inserted into the datastore or not. if(insertResult["code"] == "DATASTORE-DOCUMENTS-INSERTED") { Serial.println("Voltage is successfully logged to Grandeur."); diff --git a/examples/Datastore/Logging/Logging-esp8266/Logging-esp8266.ino b/examples/Datastore/Logging/Logging-esp8266/Logging-esp8266.ino index 551d172..7e2f382 100644 --- a/examples/Datastore/Logging/Logging-esp8266/Logging-esp8266.ino +++ b/examples/Datastore/Logging/Logging-esp8266/Logging-esp8266.ino @@ -33,7 +33,7 @@ unsigned long current = millis(); // Function prototypes void setupWiFi(void); void connectionCallback(bool status); -void insertCallback(JSONObject payload); +void insertCallback(Var payload); void setup() { Serial.begin(9600); @@ -53,7 +53,7 @@ void loop() { if(millis() - current >= 5000) { // This if-condition makes sure that the code inside this block runs only after // every five seconds. - JSONObject logs; + Var logs; logs[0]["voltage"] = analogRead(A0); myDatastore.collection("logs").insert(logs, insertCallback); // This updates the millis counter for @@ -101,7 +101,7 @@ void connectionCallback(bool status) { } } -void insertCallback(JSONObject insertResult) { +void insertCallback(Var insertResult) { // This function prints if the logs were successfully inserted into the datastore or not. if(insertResult["code"] == "DATASTORE-DOCUMENTS-INSERTED") { Serial.println("Voltage is successfully logged to Grandeur."); diff --git a/examples/Datastore/Searching/Searching-esp32/Searching-esp32.ino b/examples/Datastore/Searching/Searching-esp32/Searching-esp32.ino index c189b85..2102252 100644 --- a/examples/Datastore/Searching/Searching-esp32/Searching-esp32.ino +++ b/examples/Datastore/Searching/Searching-esp32/Searching-esp32.ino @@ -32,7 +32,7 @@ unsigned long current = millis(); void WiFiEventCallback(WiFiEvent_t event); void setupWiFi(void); void connectionCallback(bool status); -void searchCallback(JSONObject payload); +void searchCallback(Var payload); void setup() { Serial.begin(9600); @@ -53,7 +53,7 @@ void loop() { // This if-condition makes sure that the code inside this block runs only after // every five seconds. // This fetches 1st page of all the documents stored in the datastore. - JSONObject filter; + Var filter; filter["voltage"]["$gt"] = 1; myDatastore.collection("logs").search(filter, {}, 0, searchCallback); // This updates the millis counter for @@ -108,7 +108,7 @@ void connectionCallback(bool status) { } } -void searchCallback(JSONObject searchResult) { +void searchCallback(Var searchResult) { // This function prints if the datastore search for the docs was successfully or not. if(searchResult["code"] == "DATASTORE-DOCUMENTS-FETCHED") { Serial.print("Documents fetched from Grandeur: "); diff --git a/examples/Datastore/Searching/Searching-esp8266/Searching-esp8266.ino b/examples/Datastore/Searching/Searching-esp8266/Searching-esp8266.ino index 04f6a1e..18634b2 100644 --- a/examples/Datastore/Searching/Searching-esp8266/Searching-esp8266.ino +++ b/examples/Datastore/Searching/Searching-esp8266/Searching-esp8266.ino @@ -33,7 +33,7 @@ unsigned long current = millis(); // Function prototypes void setupWiFi(void); void connectionCallback(bool status); -void searchCallback(JSONObject payload); +void searchCallback(Var payload); void setup() { Serial.begin(9600); @@ -100,7 +100,7 @@ void connectionCallback(bool status) { } } -void searchCallback(JSONObject searchResult) { +void searchCallback(Var searchResult) { // This function prints if the datastore search for the docs was successfully or not. if(searchResult["code"] == "DATASTORE-DOCUMENTS-FETCHED") { Serial.print("Documents fetched from Grandeur: "); diff --git a/src/grandeurtypes.h b/src/grandeurtypes.h index 36fad2e..5e245bf 100644 --- a/src/grandeurtypes.h +++ b/src/grandeurtypes.h @@ -46,7 +46,7 @@ class Callback { // Function to generate an error void error(int type) { // Throw error - Serial.printf("[CASTING-ERROR] Was expecting %s and received %s\n", mapType(_type).c_str(), mapType(type).c_str()); + Serial.printf("[TYPE-ERROR] Was expecting %s and received %s\n", mapType(_type).c_str(), mapType(type).c_str()); } public: From cdf7928ccc197eebb674dbe1cdd10bdc4311094e Mon Sep 17 00:00:00 2001 From: Muhammad Abdullah Date: Sat, 30 Jan 2021 20:55:35 +0500 Subject: [PATCH 09/11] Readme.md is updated --- README.md | 234 ++++++++++++++++++++++-------------------------------- 1 file changed, 96 insertions(+), 138 deletions(-) diff --git a/README.md b/README.md index 5a8e309..0cf0285 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,7 @@ Project myProject; void setup() { // You can initialize device configurations like this. - myProject = grandeur.init(YourAPIKey, AuthToken); + myProject = grandeur.init(YourAPIKey, AccessToken); } void loop() {} @@ -161,7 +161,7 @@ void setup() { // This sets up the device WiFi. setupWiFi(); // You can initialize device configurations like this. - myProject = grandeur.init(YourApiKey, AuthToken); + myProject = grandeur.init(YourApiKey, AccessToken); } void loop() { @@ -239,20 +239,13 @@ void loop() { ### Fetching Device Variables and Updating Them -On Grandeur, we generally store the device data in two containers: **summary** to contain uncontrollable device variables and **parms** to contain controllable device variables. You can get and set both types using the following functions of the `Device` class: +On Grandeur, a device has a special space where you can store its variables as key-value pairs, for example, a device's voltage or current or its ON/OFF state. Keeping the online copy of device variables updated gives you many advantages. You can see if your device is ON/OFF just by fetching its `state` from Grandeur. -* `myDevice.getSummary()` -* `myDevice.getParms()` -* `myDevice.setSummary()` -* `myDevice.setParms()` - -They are all **Async functions** because they communicate with Grandeur through internet. Communication through internet takes some time and we cannot wait, for example, for device's summary variables to arrive from Grandeur -- meanwhile blocking the rest of the device program. So, what we do is, we schedule a function to be called when the summary variables and resume with rest of the device program, forgetting that we ever called `getSummary()`. When the summary variables arrive, the SDK calls our scheduled function, giving us access to summary variables inside that function. - -For now, there's only one type of function that the SDK's Async methods accept: `Callback` which accepts a `Var` as argument and returns nothing aka. `void`. +Both `data().get()` and `data().set()` are **Async functions** because they communicate with Grandeur through internet. Communication through internet takes some time and we cannot wait, for example, for a device variable to arrive from Grandeur — meanwhile blocking the rest of the device program execution. So, what we do is, we schedule a function to be called for the future when the variable arrives and resume with rest of the device program, forgetting that we ever called `data().get()`. When the variable arrives, the SDK calls our scheduled function, giving us access to that variable inside that function. Read more about **Async functions**, `Callback`, and `Var` [here][the dexterity of arduino sdk]. -Here's how we would get and set device's summary and parms: +Here's how we would get and set device variables: ```cpp #include @@ -272,29 +265,15 @@ void setupWiFi(void) { Serial.printf("\nDevice is connecting to WiFi using SSID %s and Passphrase %s.\n", ssid.c_str(), passphrase.c_str()); } -void getSummaryCallback(Var result) { +void getCallback(Var result) { // This function prints the variables stored in summary and sets the device pins. - Serial.printf("Voltage: %s\n", (int) result["deviceSummary"]["voltage"]); - Serial.printf("Current: %s\n", (int) result["deviceSummary"]["current"]); - analogWrite(A0, (int) result["deviceSummary"]["voltage"]); - analogWrite(A1, (int) result["deviceSummary"]["current"]); -} - -void getParmsCallback(Var result) { - // This function prints the variables stored in parms and sets device pins. - Serial.printf("State: %s\n", (bool) result["deviceParms"]["state"]); - digitalWrite(D0, (bool) result["deviceParms"]["state"]); + Serial.printf("Voltage: %s\n", (int) result["data"]); + analogWrite(A0, (int) result["data"]); } -void setSummaryCallback(Var result) { +void setCallback(Var result) { // This function prints the updated values of the variables stored in summary. - Serial.printf("Updated Voltage: %s\n", (int) result["update"]["voltage"]); - Serial.printf("Updated Current: %s\n", (int) result["update"]["current"]); -} - -void setParmsCallback(Var result) { - // This function prints the updated values of the variables stored in parms. - Serial.printf("Updated State: %s\n", (bool) result["update"]["state"]); + Serial.printf("Updated Voltage: %s\n", (int) result["update"]); } void setup() { @@ -302,26 +281,18 @@ void setup() { // This sets up the device WiFi. setupWiFi(); // You can initialize device configurations like this. - myProject = grandeur.init(YourApiKey, YourDeviceToken); + myProject = grandeur.init(YourApiKey, AccessToken); myDevice = myProject.device(YourDeviceID); } void loop() { if(myProject.isConnected()) { - // Getting device's summary - myDevice.getSummary(getSummaryCallback); - // Getting device's parms - myDevice.getParms(getParmsCallback); - // Updating device's summary - Var summary; - summary["voltage"] = analogRead(A0); - summary["current"] = analogRead(A1); - myDevice.setSummary(summary, setSummaryCallback); - // Updating device's parms - Var parms; - parms["state"] = digitalRead(D0); - myDevice.setParms(parms, setParmsCallback); + // Getting voltage variable + myDevice.data().get("voltage", getCallback); + // Updating voltage + int voltage = analogRead(A0); + myDevice.data().set("voltage", voltage, setCallback); } // This runs the SDK when the device WiFi is connected. @@ -329,17 +300,18 @@ void loop() { } // **RESULT** -// When the loop() starts, summary and parms are fetched. When they arrive from the cloud, their -// corresponding callbacks are called which print the variables stored in summary and parms objects -// and set the corresponding pins. -// Then the summary and parms are updated with the new values. When their updates complete, their -// callbacks are called with the updated values of their variables and these updated values are -// printed on the screen. +// When the loop() starts, voltage is fetched. When it arrives from the cloud, getCallback is +// called which prints its value and sets the A0 pin. +// Then the voltage is updated with the new value from the A0 pin. When the update completes, +// setCallback is called with the updated values of voltage which is printed. ``` ### Handling Updates From Grandeur -Device variables are distributed on the cloud in form of **summary** and **parms**. Passing a `Callback` to `onSummary()` and `onParms()` you can set **update handlers** for updates to those variables. Let's do that now: +You can not only `get()/set()` but also subscribe to a device variable, which means if an update occurs in that variable at any time, you'll instantly get notified of it. +To subscribe to a variable, you just need to pass the variable name and a function to `data().on()`. The function you pass to `data().on()` is set as an **update handlers** for that variable, which means the code inside that function will be run whenever that variable is updated. + +Let's set an update handler for device voltage now: ```cpp #include @@ -359,26 +331,19 @@ void setupWiFi(void) { Serial.printf("\nDevice is connecting to WiFi using SSID %s and Passphrase %s.\n", ssid.c_str(), passphrase.c_str()); } -void summaryUpdatedCallback(Var result) { - // This function prints the updated values of the variables stored in summary. - Serial.printf("Updated Voltage: %s\n", (int) updatedSummary["voltage"]); - Serial.printf("Updated Current: %s\n", (int) updatedSummary["current"]); -} - -void parmsUpdatedCallback(Var result) { - // This function prints the updated values of the variables stored in parms. - Serial.printf("Updated State: %s\n", (int) updatedParms["state"]); +void voltageUpdatedCallback(int voltage, const char* path) { + // This function prints the new value of the voltage variable. + Serial.printf("Updated Voltage: %d\n", voltage); } void setup() { Serial.begin(9600); setupWiFi(); - myProject = grandeur.init(YourApiKey, YourDeviceToken); + myProject = grandeur.init(YourApiKey, AccessToken); myDevice = myProject.device(YourDeviceID); - myDevice.onSummary(summaryUpdatedCallback); - myDevice.onParms(parmsUpdatedCallback); + myDevice.data().on("voltage", voltageUpdatedCallback) } void loop() { @@ -387,8 +352,8 @@ void loop() { } // **RESULT** -// Whenever an update in the device's summary or parms occur, the updated values of the -// variables are printed. +// Whenever an update in the device's voltage variable occurs, the new value of the +// voltage is printed to Serial. ``` ## Example @@ -399,7 +364,7 @@ To begin working with the **Arduino SDK**, the very first step is to [create a n ### Create a New Sketch -Create a new folder for your `arduino workspace`, create a `.ino` file in it, and open it with [Arduino IDE][Arduino IDE]. This is the sketch file where you'll write your device's program. +Create a new folder for your `arduino workspace`, create a `.ino` file in it with the same name as the folder, and open it with [Arduino IDE][Arduino IDE]. This is the sketch file where you'll write your device's program. ### Include Grandeur.h into Your Sketch @@ -411,7 +376,7 @@ After [cloning the Arduino SDK][installation] and [installing it][Installing an ### Initialize the SDK's Configurations -**Arduino SDK** takes care of your device's connection with Grandeur. To use it into your sketch, you need to initialize its configurations first. You can do that using the global object `grandeur`. Initializing the SDK returns an object of `GrandeurDevice` class which exposes all the SDK's functions. +**Arduino SDK** takes care of your device's connection with Grandeur. To use it into your sketch, you need to initialize its configurations first. You can do that using the global object `grandeur`. Initializing the SDK returns a reference to object of the `Project` class which exposes all the SDK's functions. ```cpp #include @@ -424,7 +389,7 @@ void setup() { } ``` -You can find the API Key on the [settings page][Grandeur Settings] of your project's dashboard. For the Access Token, you need to pair your device with a user account in your project first. A device can only connect to Grandeur if it's paired with a user. And only the paired user can access the device's data through its web app. For convenient testing, we have made device pairing function available on the [devices page][Grandeur Devices] too. You can find your device's ID and pair your device with a user account. If your project has no registered user yet, you can add one easily from the [accounts page][Grandeur Accounts]. +You can find the API Key on the [settings page][Grandeur Settings] of your project's dashboard. You get the **Access Token** when you register the device on Grandeur. But a device can only connect to Grandeur if it's paired with a user. And only the paired user has access to the device's data. For convenient testing, we have made device pairing function available on the [devices page][Grandeur Devices] too. You can find your device's ID and pair your device with a user account. If your project has no registered user yet, you can add one easily from the [accounts page][Grandeur Accounts]. ### Handle the device's WiFi @@ -453,7 +418,7 @@ void setup() { // This sets up the device WiFi. setupWiFi(); // You can initialize device configurations like this. - myProject = grandeur.init(YourApiKey, YourDeviceToken); + myProject = grandeur.init(YourApiKey, YourToken); } void loop() { @@ -464,7 +429,7 @@ void loop() { ### Initialize Your Device -Before doing anything, you need to initialize your device with data from the cloud to keep them both in sync. You can get all the device variables by using `getSummary()` and `getParms()` functions. Here's how you can get the device **state** from the cloud. +Before doing anything, you need to initialize your device with data from Grandeur to keep them both in sync. You can get all the device variables by using `get()` functions. Here's how you can get the device **state** from the cloud. ```cpp #include @@ -484,9 +449,9 @@ void setupWiFi(void) { Serial.printf("\nDevice is connecting to WiFi using SSID %s and Passphrase %s.\n", ssid.c_str(), passphrase.c_str()); } -void getParmsCallback(Var parms) { - if(payload["code"] == "DEVICE-PARMS-FETCHED") { - bool state = (bool) payload["deviceParms"]["state"]; +void getStateCallback(Var result) { + if(result["code"] == "DEVICE-DATA-FETCHED") { + bool state = result["data"]; // You can set a digital pin here with the state value // to switch the hardware connected to it ON/OFF. digitalWrite(D0, state); @@ -498,11 +463,11 @@ void setup() { // This sets up the device WiFi. setupWiFi(); - myProject = grandeur.init(YourApiKey, YourDeviceToken); + myProject = grandeur.init(YourApiKey, YourToken); myDevice = myProject.device(YourDeviceID); - // This gets the device's parms variables from Grandeur and passes them to - // getParmsCallback() function. - myDevice.getParms(getParmsCallback); + // This gets the device's state variable from Grandeur and passes it to + // getStateCallback() function. + myDevice.data().get("state", getStateCallback); } void loop() { @@ -513,8 +478,8 @@ void loop() { ### Set Update Handlers -Update handlers are the functions which are called when a device variable is updated on the cloud. The update could be from a user or the device itself. Without the handlers, your device would not be notified when a user turns it off from the webapp. -Here's how you can set update handlers in your sketch for the device's state stored in parms. +Update handlers are the functions which are called when a device variable is updated. The update could be from a user or the device itself. Without the handlers, your device would not be notified when a user turns it off from the web app. +Here's how you can set an update handler in your sketch for the device's state. ```cpp #include @@ -534,20 +499,19 @@ void setupWiFi(void) { Serial.printf("\nDevice is connecting to WiFi using SSID %s and Passphrase %s.\n", ssid.c_str(), passphrase.c_str()); } -void getParmsCallback(Var parms) { - if(payload["code"] == "DEVICE-PARMS-FETCHED") { - bool state = (bool) payload["deviceParms"]["state"]; +void getStateCallback(Var result) { + if(result["code"] == "DEVICE-DATA-FETCHED") { + bool state = result["data"]; // You can set a digital pin here with the state value // to switch the hardware connected to it ON/OFF. digitalWrite(D0, state); } } -void parmsUpdatedCallback(Var parms) { - bool newState = (bool) updatedParms["state"]; +void stateUpdatedCallback(bool state, const char* path) { // You can set a digital pin here with the newState value // to switch the hardware connected to it ON/OFF. - digitalWrite(D0, newState); + digitalWrite(D0, state); } void setup() { @@ -555,14 +519,14 @@ void setup() { // This sets up the device WiFi. setupWiFi(); - myProject = grandeur.init(YourApiKey, YourDeviceToken); + myProject = grandeur.init(YourApiKey, YourToken); myDevice = myProject.device(YourDeviceID); - // This gets the device's parms variables from Grandeur and passes them to - // getParmsCallback() function. - myDevice.getParms(getParmsCallback); - // This sets up the update handler for parms. When an update to parms occur on Grandeur, - // parmsUpdatedCallback() function is called. - myDevice.onParmsUpdated(parmsUpdatedCallback); + // This gets the device's state variable from Grandeur and passes it to + // getStateCallback() function. + myDevice.data().get("state", getStateCallback); + // This sets up the update handler for state. When an update to state occurs on Grandeur, + // stateUpdatedCallback() function is called. + myDevice.data().on("state", stateUpdatedCallback); } void loop() { @@ -573,7 +537,7 @@ void loop() { ### Update Device Variables -To see the live state of the device on the web app, you need to keep sending the updated state after every few seconds. Since we've stored the device's state in **Parms**, we'll use the `setParms()` function to update the state value. +To see the live state of the device on the web app, you need to keep sending the updated state after every few seconds. We'll use the `set()` function to update the state value. ```cpp #include @@ -593,25 +557,24 @@ void setupWiFi(void) { Serial.printf("\nDevice is connecting to WiFi using SSID %s and Passphrase %s.\n", ssid.c_str(), passphrase.c_str()); } -void getParmsCallback(Var parms) { - if(payload["code"] == "DEVICE-PARMS-FETCHED") { - bool state = (bool) payload["deviceParms"]["state"]; +void getStateCallback(Var result) { + if(result["code"] == "DEVICE-DATA-FETCHED") { + bool state = result["data"]; // You can set a digital pin here with the state value // to switch the hardware connected to it ON/OFF. digitalWrite(D0, state); } } -void parmsUpdatedCallback(Var parms) { - bool newState = (bool) updatedParms["state"]; +void stateUpdatedCallback(bool state, const char* path) { // You can set a digital pin here with the newState value // to switch the hardware connected to it ON/OFF. - digitalWrite(D0, newState); + digitalWrite(D0, state); } -void setParmsCallback(Var parms) { - if(result["code"] == "DEVICE-PARMS-UPDATED") { - Serial.printf("State is updated to: %d\n", (bool) payload["update"]["state"]); +void setStateCallback(Var result) { + if(result["code"] == "DEVICE-DATA-UPDATED") { + Serial.printf("State is updated to: %d\n", (bool) result["update"]); } } @@ -620,23 +583,21 @@ void setup() { // This sets up the device WiFi. setupWiFi(); - myProject = grandeur.init(YourApiKey, YourDeviceToken); + myProject = grandeur.init(YourApiKey, YourToken); myDevice = myProject.device(YourDeviceID); - // This gets the device's parms variables from Grandeur and passes them to - // getParmsCallback() function. - myDevice.getParms(getParmsCallback); - // This sets up the update handler for parms. When an update to parms occur on Grandeur, - // parmsUpdatedCallback() function is called. - myDevice.onParmsUpdated(parmsUpdatedCallback); + // This gets the device's state variable from Grandeur and passes it to + // getStateCallback() function. + myDevice.data().get("state", getStateCallback); + // This sets up the update handler for state. When an update to state occurs on Grandeur, + // stateUpdatedCallback() function is called. + myDevice.data().on("state", stateUpdatedCallback); } void loop() { - // Parms container to store device's state. - Var parms; - parms["state"] = digitalRead(D0); - // This sends the updated parms to Grandeur and calls setParmsCallback() when - // the response from the cloud arrives. - myDevice.setParms(parms, setParmsCallback); + bool state = digitalRead(D0); + // This sends the updated state to Grandeur and calls setStateCallback() when + // Grandeur acknowledges the update. + myDevice.data().set("state", state, setStateCallback); // This runs the SDK when the device WiFi is connected. myProject.loop(WiFi.status() == WL_CONNECTED); @@ -659,35 +620,26 @@ The Arduino SDK is aimed at providing extremely to-the-point functions, being al * **Arduino SDK** is event-driven. You can set **event handler** for device's connection or disconnection with Grandeur by using [`onConnection()`][onConnection]. So, when the device connects or disconnects from the cloud, the function passed to `onConnection()` is called. -* You can also set **update handlers** for device's summary and parms using [`onSummary()`][onSummary] and [`onParms()`][onParms]. So, when the any of the device variables stored in summary or parms is updated, the function passed to `onSummary()` or `onParmsUpdated()` is called. +* You can also set **update handlers** for device variables using [`data().on()`][on] function. So, when any of the device variables is updated, the corresponding function passed to `on()` is called. -* **Async functions** are what make the event-drive of the SDK possible. They do all the same things as regular functions plus one extra. They receive a function parameter which they schedule for later. For example, in the `GrandeurDevice` class, all of the following are Async functions: +* **Async functions** are what make the event-drive of the SDK possible. They do all the same things as regular functions plus one extra. They receive a function parameter which they schedule for later. For example, all of the following are Async functions: - * `onConnection(Callback callback)` - * `onSummary(Callback callback)` - * `onParmsUpdated(Callback callback)` - * `getSummary(Callback callback)` - * `getParms(Callback callback)` - * `setSummary(Var summary, Callback callback)` - * `setParms(Var parms, Callback callback)` - - `getParms()` for example, requests the cloud for the device's parms and schedules the `callback` function for when the parms arrive, because obviously, they don't arrive instantaneously; there is always some latency involved in web communications. + * `project.onConnection(Callback callback)` + * `project.device().data().on(String path, function callback)` + * `project.device().data().get(String path, function callback)` + * `project.device().data().set(String path, Var data, function callback)` -* There is a special type of function defined in **Arduino SDK** as [`Callback`][callback]. It's nothing but a regular function of the form: - ```cpp - void callback(Var result) {} - ``` - For now, it is the only function type that the Async functions of SDK accept as argument. + `get()` for example, requests Grandeur for a device variable and schedules the `callback` function for when the variable arrives, because obviously, they don't arrive instantaneously; there is always some latency involved in web communications. -* [`Var`][var] is a special variable type which acts like a container for other variables, just like a javascript object or a C++ map. You can store variables in it as key-value pairs. This what summary and parms are -- container for other variables aka. `Var`s. +* [`Var`][var] is a special variable type which can take form of any other type including int, double, String, etc, like in those dynamic typed languages like javascript. But it can also act like a container for other variables, like a javascript object or a C++ map, to form JSON. You can store variables in it as key-value pairs. This is device data space is — a container for device variables aka. `Var`. ```cpp -Var summary; -summary["foo"] = "This is foo"; -summary["bar"] = true; -summary["foobar"]["foo"] = "This is foo inside foobar"; +Var json; // The root +json["foo"] = "This is foo"; // "foo" key in json +json["bar"] = true; // "bar" key in json +json["foobar"]["foo"] = "This is foo inside foobar"; // "foo" key in "foobar" key in json -// In JSON, summary would look like: +// In JSON, json would look like: // { // "foo": "This is foo", // "bar": true, @@ -695,6 +647,12 @@ summary["foobar"]["foo"] = "This is foo inside foobar"; // "foo": "This is foo inside foobar" // } // } + +// You can also store anything in Var. +Var x = 5; +x = "hello"; + +Serial.println(x); // Prints: hello ``` To see the **Arduino SDK** in action, jump to [Example][Example]. From 11cefe467175ef449c0dae292bda09c981dfbe97 Mon Sep 17 00:00:00 2001 From: Muhammad Abdullah Date: Sat, 30 Jan 2021 23:05:39 +0500 Subject: [PATCH 10/11] Readme.md is updated --- .../CrossListening-esp32.ino | 123 +++++++----------- .../CrossListening-esp8266.ino | 115 +++++++--------- .../DashListening-App-esp32.ino | 72 ++++------ .../DashListening-App-esp8266.ino | 70 ++++------ .../DashListening-Device-esp32.ino | 47 ++++--- .../DashListening-Device-esp8266.ino | 47 ++++--- .../Logging/Logging-esp32/Logging-esp32.ino | 11 +- .../Logging-esp8266/Logging-esp8266.ino | 11 +- .../Searching-esp32/Searching-esp32.ino | 13 +- .../Searching-esp8266/Searching-esp8266.ino | 13 +- 10 files changed, 209 insertions(+), 313 deletions(-) diff --git a/examples/CrossListening/CrossListening-esp32/CrossListening-esp32.ino b/examples/CrossListening/CrossListening-esp32/CrossListening-esp32.ino index 16d25a7..c4dede3 100644 --- a/examples/CrossListening/CrossListening-esp32/CrossListening-esp32.ino +++ b/examples/CrossListening/CrossListening-esp32/CrossListening-esp32.ino @@ -29,60 +29,50 @@ String token = "YOUR-ACCESS-TOKEN"; const char* ssid = "YOUR-WIFI-SSID"; const char* passphrase = "YOUR-WIFI-PASSWORD"; -// Declaring and initializing other variables +// Declaring and initializing other Variables unsigned long current = millis(); -Project myProject; -Device myDevice; +Project project; +Data data; int statePin = 4; int voltagePin = 2; // Function prototypes void WiFiEventCallback(WiFiEvent_t event); void setupWiFi(void); -void connectionCallback(Var updateObject); +void connectionCallback(bool state); void initializeState(Var getResult); -void parmsUpdatedCallback(Var updatedParms); -void summarySetCallback(Var setResult); -void parmsSetCallback(Var setResult); - +void stateUpdatedCallback(bool state, const char* path); +void voltageSetCallback(Var setResult); void setup() { Serial.begin(9600); // This sets up the device WiFi. setupWiFi(); - // This initializes the SDK's configurations and returns a new object of Project class. - myProject = grandeur.init(apiKey, token); - // Getting object of Device class. - myDevice = myProject.device(deviceID); - // This schedules the connectionCallback() function to be called when connection with the cloud + // This initializes the SDK's configurations and returns reference to your project. + project = grandeur.init(apiKey, token); + // Getting reference to your device. + data = project.device(deviceID).data(); + // This schedules the connectionCallback() function to be called when connection with Grandeur // is made/broken. - myProject.onConnection(connectionCallback); - // This schedules parmsUpdatedCallback() function to be called when variable stored - // in device's parms are changed on Grandeur. - myDevice.onParms(parmsUpdatedCallback); + project.onConnection(connectionCallback); + // This schedules stateUpdatedCallback() function to be called when the device state is + // changed on Grandeur. + data.on("state", stateUpdatedCallback); } void loop() { // In this loop() function, after every five seconds, we send the updated values of our // device's voltage and state to Grandeur. - if(myProject.isConnected()) { + if(project.isConnected()) { if(millis() - current >= 5000) { // This if-condition makes sure that the code inside this block runs only after // every five seconds. - Serial.println("Setting Summary"); - Var summary; - summary["voltage"] = analogRead(voltagePin); - // This updates the summary of our device on Grandeur and schedules summarySetCallback() - // function to be called when Grandeur responds with the SUMMARY UPDATED message. - myDevice.setSummary(summary, summarySetCallback); - - Serial.println("Setting Parms"); - Var parms; - parms["state"] = digitalRead(statePin); - // This updates the parms of our device on Grandeur and schedules parmsSetCallback() - // function to be called when Grandeur responds with the PARMS UPDATED message. - myDevice.setParms(parms, parmsSetCallback); + Serial.println("Setting Voltage"); + int voltage = analogRead(voltagePin); + // This updates the voltage of our device on Grandeur and schedules voltageSetCallback() + // function to be called when Grandeur responds with the DATA UPDATED message. + data.set("voltage", voltage, voltageSetCallback); // This updates the millis counter for // the five seconds scheduler. @@ -91,7 +81,7 @@ void loop() { } // This runs the SDK only when the WiFi is connected. - myProject.loop(WiFi.status() == WL_CONNECTED); + project.loop(WiFi.status() == WL_CONNECTED); } void WiFiEventCallback(WiFiEvent_t event) { @@ -121,69 +111,56 @@ void setupWiFi(void) { Serial.printf("\nDevice is connecting to WiFi using SSID %s and Passphrase %s.\n", ssid, passphrase); } -void connectionCallback(bool state) { - switch(state) { +void connectionCallback(bool status) { + switch(status) { case CONNECTED: - // On successful connection with the cloud, we initialize the device's *state*. - // To do that, we get device parms from the cloud and set the *state pin* to the - // value of *state* in those parms. - Serial.println("Device is connected to the cloud."); - myDevice.getParms(initializeState); - Serial.println("Listening for parms update from the cloud..."); + // On successful connection with Grandeur, we initialize the device's *state*. + // To do that, we get device state from Grandeur and set the *state pin* to its + // value. + Serial.println("Device is connected with Grandeur."); + data.get("state", initializeState); + Serial.println("Listening for state update from Grandeur..."); // Initializing the millis counter for the five // seconds timer. current = millis(); break; case DISCONNECTED: - Serial.println("Device is disconnected from the cloud."); + Serial.println("Device's connection with Grandeur is broken."); break; } } void initializeState(Var getResult) { - // This function sets the *state pin* to the *state value* that we received in parms - // from the cloud. - if(getResult["code"] == "DEVICE-PARMS-FETCHED") { - int state = getResult["deviceParms"]["state"]; + // This function sets the *state pin* to the *state value* that we received in data + // from Grandeur. + if(getResult["code"] == "DEVICE-DATA-FETCHED") { + int state = getResult["data"]; + Serial.printf("State is: %d\n", state); digitalWrite(statePin, state); return; } - // If the parms could not be fetched. - Serial.println("Failed to Fetch Parms"); + // If the data could not be fetched. + Serial.println("Failed to Fetch State"); return; } -void parmsUpdatedCallback(Var updatedParms) { - // This function gets the *updated state* from the device parms and set the *state pin* - // with *state value*. - Serial.printf("Updated State is: %d\n", (bool) updatedParms["state"]); - digitalWrite(statePin, (bool) updatedParms["state"]); +void stateUpdatedCallback(bool state, const char* path) { + // This function gets the *updated state* from Grandeur and set the *state pin* + // with its value. + Serial.printf("Updated State is: %d\n", state); + digitalWrite(statePin, state); } -void summarySetCallback(Var setResult) { - if(setResult["code"] == "DEVICE-SUMMARY-UPDATED") { - Serial.printf("Voltage is updated to: %d\n", (int) setResult["update"]["voltage"]); +void voltageSetCallback(Var setResult) { + if(setResult["code"] == "DEVICE-DATA-UPDATED") { + Serial.printf("Voltage is updated to: %d\n", (int) setResult["update"]); /* You can set some pins or trigger events here which depend on successful - ** device summary update. + ** voltage update. */ return; } - // If the summary could not be updated. - Serial.println("Failed to Update Summary"); + // If the voltage could not be updated. + Serial.println("Failed to Update Voltage"); return; -} - -void parmsSetCallback(Var setResult) { - if(setResult["code"] == "DEVICE-PARMS-UPDATED") { - Serial.printf("State is updated to: %d\n", (bool) setResult["update"]["state"]); - - /* You can set some pins or trigger events here which depend on successful - ** device parms update. - */ - return; - } - // If the parms could not be updated. - Serial.println("Failed to Update Parms"); - return; -} +} \ No newline at end of file diff --git a/examples/CrossListening/CrossListening-esp8266/CrossListening-esp8266.ino b/examples/CrossListening/CrossListening-esp8266/CrossListening-esp8266.ino index 7503b66..e811865 100644 --- a/examples/CrossListening/CrossListening-esp8266/CrossListening-esp8266.ino +++ b/examples/CrossListening/CrossListening-esp8266/CrossListening-esp8266.ino @@ -40,50 +40,40 @@ int voltagePin = A0; // Function prototypes void setupWiFi(void); -void connectionCallback(Var updateObject); +void connectionCallback(bool state); void initializeState(Var getResult); -void parmsUpdatedCallback(Var updatedParms); -void summarySetCallback(Var setResult); -void parmsSetCallback(Var setResult); - +void stateUpdatedCallback(bool state, const char* path); +void voltageSetCallback(Var setResult); void setup() { Serial.begin(9600); // This sets up the device WiFi. setupWiFi(); - // This initializes the SDK's configurations and returns a new object of Project class. - myProject = grandeur.init(apiKey, token); - // Getting object of Device class. - myDevice = myProject.device(deviceID); - // This schedules the connectionCallback() function to be called when connection with the cloud + // This initializes the SDK's configurations and returns reference to your project. + project = grandeur.init(apiKey, token); + // Getting reference to your device. + data = project.device(deviceID).data(); + // This schedules the connectionCallback() function to be called when connection with Grandeur // is made/broken. - myProject.onConnection(connectionCallback); - // This schedules parmsUpdatedCallback() function to be called when variable stored - // in device's parms are changed on Grandeur. - myDevice.onParms(parmsUpdatedCallback); + project.onConnection(connectionCallback); + // This schedules stateUpdatedCallback() function to be called when the device state is + // changed on Grandeur. + data.on("state", stateUpdatedCallback); } void loop() { // In this loop() function, after every five seconds, we send the updated values of our // device's voltage and state to Grandeur. - if(myProject.isConnected()) { + if(project.isConnected()) { if(millis() - current >= 5000) { // This if-condition makes sure that the code inside this block runs only after // every five seconds. - Serial.println("Setting Summary"); - Var summary; - summary["voltage"] = analogRead(voltagePin); - // This updates the summary of our device on Grandeur and schedules summarySetCallback() - // function to be called when Grandeur responds with the SUMMARY UPDATED message. - myDevice.setSummary(summary, summarySetCallback); - - Serial.println("Setting Parms"); - Var parms; - parms["state"] = digitalRead(statePin); - // This updates the parms of our device on Grandeur and schedules parmsSetCallback() - // function to be called when Grandeur responds with the PARMS UPDATED message. - myDevice.setParms(parms, parmsSetCallback); + Serial.println("Setting Voltage"); + int voltage = analogRead(voltagePin); + // This updates the voltage of our device on Grandeur and schedules voltageSetCallback() + // function to be called when Grandeur responds with the DATA UPDATED message. + data.set("voltage", voltage, voltageSetCallback); // This updates the millis counter for // the five seconds scheduler. @@ -92,7 +82,7 @@ void loop() { } // This runs the SDK only when the WiFi is connected. - myProject.loop(WiFi.status() == WL_CONNECTED); + project.loop(WiFi.status() == WL_CONNECTED); } void setupWiFi(void) { @@ -115,69 +105,56 @@ void setupWiFi(void) { Serial.printf("\nDevice is connecting to WiFi using SSID %s and Passphrase %s.\n", ssid.c_str(), passphrase.c_str()); } -void connectionCallback(bool state) { - switch(state) { +void connectionCallback(bool status) { + switch(status) { case CONNECTED: - // On successful connection with the cloud, we initialize the device's *state*. - // To do that, we get device parms from the cloud and set the *state pin* to the - // value of *state* in those parms. - Serial.println("Device is connected to the cloud."); - myDevice.getParms(initializeState); - Serial.println("Listening for parms update from the cloud..."); + // On successful connection with Grandeur, we initialize the device's *state*. + // To do that, we get device state from Grandeur and set the *state pin* to its + // value. + Serial.println("Device is connected with Grandeur."); + data.get("state", initializeState); + Serial.println("Listening for state update from Grandeur..."); // Initializing the millis counter for the five // seconds timer. current = millis(); break; case DISCONNECTED: - Serial.println("Device is disconnected from the cloud."); + Serial.println("Device's connection with Grandeur is broken."); break; } } void initializeState(Var getResult) { - // This function sets the *state pin* to the *state value* that we received in parms - // from the cloud. - if(getResult["code"] == "DEVICE-PARMS-FETCHED") { - int state = getResult["deviceParms"]["state"]; + // This function sets the *state pin* to the *state value* that we received in data + // from Grandeur. + if(getResult["code"] == "DEVICE-DATA-FETCHED") { + int state = getResult["data"]; + Serial.printf("State is: %d\n", state); digitalWrite(statePin, state); return; } - // If the parms could not be fetched. - Serial.println("Failed to Fetch Parms"); + // If the data could not be fetched. + Serial.println("Failed to Fetch State"); return; } -void parmsUpdatedCallback(Var updatedParms) { - // This function gets the *updated state* from the device parms and set the *state pin* - // with *state value*. - Serial.printf("Updated State is: %d\n", (bool) updatedParms["state"]); - digitalWrite(statePin, (bool) updatedParms["state"]); +void stateUpdatedCallback(bool state, const char* path) { + // This function gets the *updated state* from Grandeur and set the *state pin* + // with its value. + Serial.printf("Updated State is: %d\n", state); + digitalWrite(statePin, state); } -void summarySetCallback(Var setResult) { - if(setResult["code"] == "DEVICE-SUMMARY-UPDATED") { - Serial.printf("Voltage is updated to: %d\n", (int) setResult["update"]["voltage"]); +void voltageSetCallback(Var setResult) { + if(setResult["code"] == "DEVICE-DATA-UPDATED") { + Serial.printf("Voltage is updated to: %d\n", (int) setResult["update"]); /* You can set some pins or trigger events here which depend on successful - ** device summary update. - */ - return; - } - // If the summary could not be updated. - Serial.println("Failed to Update Summary"); - return; -} - -void parmsSetCallback(Var setResult) { - if(setResult["code"] == "DEVICE-PARMS-UPDATED") { - Serial.printf("State is updated to: %d\n", (bool) setResult["update"]["state"]); - - /* You can set some pins or trigger events here which depend on successful - ** device parms update. + ** voltage update. */ return; } - // If the parms could not be updated. - Serial.println("Failed to Update Parms"); + // If the voltage could not be updated. + Serial.println("Failed to Update Voltage"); return; } \ No newline at end of file diff --git a/examples/DashListening-App/DashListening-App-esp32/DashListening-App-esp32.ino b/examples/DashListening-App/DashListening-App-esp32/DashListening-App-esp32.ino index 8fd9ed5..bc5dc87 100644 --- a/examples/DashListening-App/DashListening-App-esp32/DashListening-App-esp32.ino +++ b/examples/DashListening-App/DashListening-App-esp32/DashListening-App-esp32.ino @@ -37,8 +37,7 @@ void WiFiEventCallback(WiFiEvent_t event); void setupWiFi(void); void connectionCallback(bool state); void initializeState(Var getResult); -void summarySetCallback(Var setResult); -void parmsSetCallback(Var setResult); +void voltageSetCallback(Var setResult); void setup() { Serial.begin(9600); @@ -48,7 +47,7 @@ void setup() { myProject = grandeur.init(apiKey, token); // Getting object of Device class. myDevice = myProject.device(deviceID); - // This schedules the connectionCallback() function to be called when connection with the cloud + // This schedules the connectionCallback() function to be called when connection with Grandeur // is made/broken. myProject.onConnection(connectionCallback); } @@ -61,19 +60,11 @@ void loop() { // This if-condition makes sure that the code inside this block runs only after // every five seconds. - Serial.println("Setting Summary"); - Var summary; - summary["voltage"] = analogRead(voltagePin); - // This updates the summary of our device on Grandeur and schedules summarySetCallback() - // function to be called when Grandeur responds with the SUMMARY UPDATED message. - myDevice.setSummary(summary, summarySetCallback); - - Serial.println("Setting Parms"); - Var parms; - parms["state"] = digitalRead(statePin); - // This updates the parms of our device on Grandeur and schedules parmsSetCallback() - // function to be called when Grandeur responds with the PARMS UPDATED message. - myDevice.setParms(parms, parmsSetCallback); + Serial.println("Setting Voltage"); + int voltage = analogRead(voltagePin); + // This updates the voltage variable and schedules voltageSetCallback() + // function to be called when Grandeur acknowledges the update. + myDevice.data().set("voltage", voltage, voltageSetCallback); // This updates the millis counter for // the five seconds scheduler. @@ -115,58 +106,43 @@ void setupWiFi(void) { void connectionCallback(bool state) { switch(state) { case CONNECTED: - // On successful connection with the cloud, we initialize the device's *state*. - // To do that, we get device parms from the cloud and set the *state pin* to the value of *state* in those parms. - Serial.println("Device is connected to the cloud."); - myDevice.getParms(initializeState); + // On successful connection with Grandeur, we initialize the device's *state*. + // To do that, we set the *state pin* to the value of *state* from Grandeur. + Serial.println("Device is connected with Grandeur."); + myDevice.data().get("state", initializeState); // Initializing the millis counter for the five // seconds timer. current = millis(); break; case DISCONNECTED: - Serial.println("Device is disconnected from the cloud."); + Serial.println("Device's connection with Grandeur is broken."); break; } } void initializeState(Var getResult) { - // This function sets the *state pin* to the *state value* that we received in parms - // from the cloud. - if(getResult["code"] == "DEVICE-PARMS-FETCHED") { - int state = getResult["deviceParms"]["state"]; + // This function sets the *state pin* to the *state value*. + if(getResult["code"] == "DEVICE-DATA-FETCHED") { + int state = getResult["data"]; digitalWrite(statePin, state); return; } - // If the parms could not be fetched. - Serial.println("Failed to Fetch Parms"); + // If the state could not be fetched. + Serial.println("Failed to Fetch State"); return; } -void summarySetCallback(Var setResult) { - if(setResult["code"] == "DEVICE-SUMMARY-UPDATED") { - Serial.printf("Voltage is updated to: %d\n", (int) setResult["update"]["voltage"]); +void voltageSetCallback(Var setResult) { + if(setResult["code"] == "DEVICE-DATA-UPDATED") { + Serial.printf("Voltage is updated to: %d\n", (int) setResult["update"]); /* You can set some pins or trigger events here which depend on successful - ** device summary update. - */ - return; - } - // If the summary could not be updated. - Serial.println("Failed to Update Summary"); - return; -} - -void parmsSetCallback(Var setResult) { - if(setResult["code"] == "DEVICE-PARMS-UPDATED") { - Serial.printf("State is updated to: %d\n", (bool) setResult["update"]["state"]); - - /* You can set some pins or trigger events here which depend on successful - ** device parms update. + ** voltage update. */ return; } - // If the parms could not be updated. - Serial.println("Failed to Update Parms"); + // If the voltage could not be updated. + Serial.println("Failed to Update Voltage"); return; -} +} \ No newline at end of file diff --git a/examples/DashListening-App/DashListening-App-esp8266/DashListening-App-esp8266.ino b/examples/DashListening-App/DashListening-App-esp8266/DashListening-App-esp8266.ino index 55984d7..7d04de4 100644 --- a/examples/DashListening-App/DashListening-App-esp8266/DashListening-App-esp8266.ino +++ b/examples/DashListening-App/DashListening-App-esp8266/DashListening-App-esp8266.ino @@ -38,8 +38,7 @@ int voltagePin = A0; void setupWiFi(void); void connectionCallback(bool state); void initializeState(Var getResult); -void summarySetCallback(Var setResult); -void parmsSetCallback(Var setResult); +void voltageSetCallback(Var setResult); void setup() { Serial.begin(9600); @@ -49,7 +48,7 @@ void setup() { myProject = grandeur.init(apiKey, token); // Getting object of Device class. myDevice = myProject.device(deviceID); - // This schedules the connectionCallback() function to be called when connection with the cloud + // This schedules the connectionCallback() function to be called when connection with Grandeur // is made/broken. myProject.onConnection(connectionCallback); } @@ -62,19 +61,11 @@ void loop() { // This if-condition makes sure that the code inside this block runs only after // every five seconds. - Serial.println("Setting Summary"); - Var summary; - summary["voltage"] = analogRead(voltagePin); - // This updates the summary of our device on Grandeur and schedules summarySetCallback() - // function to be called when Grandeur responds with the SUMMARY UPDATED message. - myDevice.setSummary(summary, summarySetCallback); - - Serial.println("Setting Parms"); - Var parms; - parms["state"] = digitalRead(statePin); - // This updates the parms of our device on Grandeur and schedules parmsSetCallback() - // function to be called when Grandeur responds with the PARMS UPDATED message. - myDevice.setParms(parms, parmsSetCallback); + Serial.println("Setting Voltage"); + int voltage = analogRead(voltagePin); + // This updates the voltage variable and schedules voltageSetCallback() + // function to be called when Grandeur acknowledges the update. + myDevice.data().set("voltage", voltage, voltageSetCallback); // This updates the millis counter for // the five seconds scheduler. @@ -109,58 +100,43 @@ void setupWiFi(void) { void connectionCallback(bool state) { switch(state) { case CONNECTED: - // On successful connection with the cloud, we initialize the device's *state*. - // To do that, we get device parms from the cloud and set the *state pin* to the value of *state* in those parms. - Serial.println("Device is connected to the cloud."); - myDevice.getParms(initializeState); + // On successful connection with Grandeur, we initialize the device's *state*. + // To do that, we set the *state pin* to the value of *state* from Grandeur. + Serial.println("Device is connected with Grandeur."); + myDevice.data().get("state", initializeState); // Initializing the millis counter for the five // seconds timer. current = millis(); break; case DISCONNECTED: - Serial.println("Device is disconnected from the cloud."); + Serial.println("Device's connection with Grandeur is broken."); break; } } void initializeState(Var getResult) { - // This function sets the *state pin* to the *state value* that we received in parms - // from the cloud. - if(getResult["code"] == "DEVICE-PARMS-FETCHED") { - int state = getResult["deviceParms"]["state"]; + // This function sets the *state pin* to the *state value*. + if(getResult["code"] == "DEVICE-DATA-FETCHED") { + int state = getResult["data"]; digitalWrite(statePin, state); return; } - // If the parms could not be fetched. - Serial.println("Failed to Fetch Parms"); + // If the state could not be fetched. + Serial.println("Failed to Fetch State"); return; } -void summarySetCallback(Var setResult) { - if(setResult["code"] == "DEVICE-SUMMARY-UPDATED") { - Serial.printf("Voltage is updated to: %d\n", (int) setResult["update"]["voltage"]); +void voltageSetCallback(Var setResult) { + if(setResult["code"] == "DEVICE-DATA-UPDATED") { + Serial.printf("Voltage is updated to: %d\n", (int) setResult["update"]); /* You can set some pins or trigger events here which depend on successful - ** device summary update. - */ - return; - } - // If the summary could not be updated. - Serial.println("Failed to Update Summary"); - return; -} - -void parmsSetCallback(Var setResult) { - if(setResult["code"] == "DEVICE-PARMS-UPDATED") { - Serial.printf("State is updated to: %d\n", (bool) setResult["update"]["state"]); - - /* You can set some pins or trigger events here which depend on successful - ** device parms update. + ** voltage update. */ return; } - // If the parms could not be updated. - Serial.println("Failed to Update Parms"); + // If the voltage could not be updated. + Serial.println("Failed to Update Voltage"); return; } \ No newline at end of file diff --git a/examples/DashListening-Device/DashListening-Device-esp32/DashListening-Device-esp32.ino b/examples/DashListening-Device/DashListening-Device-esp32/DashListening-Device-esp32.ino index 7454fd1..5fb8154 100644 --- a/examples/DashListening-Device/DashListening-Device-esp32/DashListening-Device-esp32.ino +++ b/examples/DashListening-Device/DashListening-Device-esp32/DashListening-Device-esp32.ino @@ -35,22 +35,22 @@ void WiFiEventCallback(WiFiEvent_t event); void setupWiFi(void); void connectionCallback(bool state); void initializeState(Var getResult); -void parmsUpdatedCallback(Var updatedParms); +void stateUpdatedCallback(bool state, const char* path); void setup() { Serial.begin(9600); // This sets up the device WiFi. setupWiFi(); - // This initializes the SDK's configurations and returns a new object of GrandeurDevice class. + // This initializes the SDK's configurations and returns a reference to object of the Project class. myProject = grandeur.init(apiKey, token); - // Getting object of Device class. + // Getting reference to object of Device class. myDevice = myProject.device(deviceID); - // This schedules the connectionCallback() function to be called when connection with the cloud + // This schedules the connectionCallback() function to be called when connection with Grandeur // is made/broken. myProject.onConnection(connectionCallback); - // This schedules parmsUpdatedCallback() function to be called when variable stored - // in device's parms are changed on Grandeur. - myDevice.onParms(parmsUpdatedCallback); + // This schedules stateUpdatedCallback() function to be called when state variable + // is changed on Grandeur. + myDevice.data().on("state", stateUpdatedCallback); } void loop() { @@ -88,35 +88,32 @@ void setupWiFi(void) { void connectionCallback(bool status) { switch(status) { case CONNECTED: - // On successful connection with the cloud, we initialize the device's *state*. - // To do that, we get device parms from the cloud and set the *state pin* to the - // value of *state* in those parms. - Serial.println("Device is connected to the cloud."); - myDevice.getParms(initializeState); - Serial.println("Listening for parms update from the cloud..."); + // On successful connection with the cloud, we initialize the device's *state* pin. + // To do that, we get state variable from Grandeur and set the *state pin* to its value. + Serial.println("Device is connected with Grandeur."); + myDevice.data().get("state", initializeState); + Serial.println("Listening for update in state..."); break; case DISCONNECTED: - Serial.println("Device is disconnected from the cloud."); + Serial.println("Device's connection with Grandeur is broken."); break; } } void initializeState(Var getResult) { - // This function sets the *state pin* to the *state value* that we received in parms - // from the cloud. - if(getResult["code"] == "DEVICE-PARMS-FETCHED") { - int state = getResult["deviceParms"]["state"]; + // This function sets the *state pin* to the *state value* that we received from Grandeur. + if(getResult["code"] == "DEVICE-DATA-FETCHED") { + int state = getResult["data"]; digitalWrite(statePin, state); return; } - // If the parms could not be fetched. - Serial.println("Failed to Fetch Parms"); + // If the state could not be fetched. + Serial.println("Failed to Fetch State"); return; } -void parmsUpdatedCallback(Var updatedParms) { - // This function gets the *updated state* from the device parms and set the *state pin* - // with *state value*. - Serial.printf("Updated State is: %d\n", (bool) updatedParms["state"]); - digitalWrite(statePin, (bool) updatedParms["state"]); +void stateUpdatedCallback(bool state, const char* path) { + // This function sets the *state pin* to *state value*. + Serial.printf("Updated State is: %d\n", state); + digitalWrite(statePin, state); } \ No newline at end of file diff --git a/examples/DashListening-Device/DashListening-Device-esp8266/DashListening-Device-esp8266.ino b/examples/DashListening-Device/DashListening-Device-esp8266/DashListening-Device-esp8266.ino index 47a59ad..40df911 100644 --- a/examples/DashListening-Device/DashListening-Device-esp8266/DashListening-Device-esp8266.ino +++ b/examples/DashListening-Device/DashListening-Device-esp8266/DashListening-Device-esp8266.ino @@ -36,22 +36,22 @@ int statePin = D0; void setupWiFi(void); void connectionCallback(bool state); void initializeState(Var getResult); -void parmsUpdatedCallback(Var updatedParms); +void stateUpdatedCallback(bool state, const char* path); void setup() { Serial.begin(9600); // This sets up the device WiFi. setupWiFi(); - // This initializes the SDK's configurations and returns a new object of GrandeurDevice class. + // This initializes the SDK's configurations and returns a reference to object of the Project class. myProject = grandeur.init(apiKey, token); - // Getting object of Device class. + // Getting reference to object of Device class. myDevice = myProject.device(deviceID); - // This schedules the connectionCallback() function to be called when connection with the cloud + // This schedules the connectionCallback() function to be called when connection with Grandeur // is made/broken. myProject.onConnection(connectionCallback); - // This schedules parmsUpdatedCallback() function to be called when variable stored - // in device's parms are changed on Grandeur. - myDevice.onParms(parmsUpdatedCallback); + // This schedules stateUpdatedCallback() function to be called when state variable + // is changed on Grandeur. + myDevice.data().on("state", stateUpdatedCallback); } void loop() { @@ -82,35 +82,32 @@ void setupWiFi(void) { void connectionCallback(bool status) { switch(status) { case CONNECTED: - // On successful connection with the cloud, we initialize the device's *state*. - // To do that, we get device parms from the cloud and set the *state pin* to the - // value of *state* in those parms. - Serial.println("Device is connected to the cloud."); - myDevice.getParms(initializeState); - Serial.println("Listening for parms update from the cloud..."); + // On successful connection with the cloud, we initialize the device's *state* pin. + // To do that, we get state variable from Grandeur and set the *state pin* to its value. + Serial.println("Device is connected with Grandeur."); + myDevice.data().get("state", initializeState); + Serial.println("Listening for update in state..."); break; case DISCONNECTED: - Serial.println("Device is disconnected from the cloud."); + Serial.println("Device's connection with Grandeur is broken."); break; } } void initializeState(Var getResult) { - // This function sets the *state pin* to the *state value* that we received in parms - // from the cloud. - if(getResult["code"] == "DEVICE-PARMS-FETCHED") { - int state = getResult["deviceParms"]["state"]; + // This function sets the *state pin* to the *state value* that we received from Grandeur. + if(getResult["code"] == "DEVICE-DATA-FETCHED") { + int state = getResult["data"]; digitalWrite(statePin, state); return; } - // If the parms could not be fetched. - Serial.println("Failed to Fetch Parms"); + // If the state could not be fetched. + Serial.println("Failed to Fetch State"); return; } -void parmsUpdatedCallback(Var updatedParms) { - // This function gets the *updated state* from the device parms and set the *state pin* - // with *state value*. - Serial.printf("Updated State is: %d\n", (bool) updatedParms["state"]); - digitalWrite(statePin, (bool) updatedParms["state"]); +void stateUpdatedCallback(bool state, const char* path) { + // This function sets the *state pin* to *state value*. + Serial.printf("Updated State is: %d\n", state); + digitalWrite(statePin, state); } \ No newline at end of file diff --git a/examples/Datastore/Logging/Logging-esp32/Logging-esp32.ino b/examples/Datastore/Logging/Logging-esp32/Logging-esp32.ino index f57dfd5..c35b11e 100644 --- a/examples/Datastore/Logging/Logging-esp32/Logging-esp32.ino +++ b/examples/Datastore/Logging/Logging-esp32/Logging-esp32.ino @@ -42,7 +42,7 @@ void setup() { myProject = grandeur.init(apiKey, token); // Getting object of Datastore class. myDatastore = myProject.datastore(); - // This schedules the connectionCallback() function to be called when connection with the cloud + // This schedules the connectionCallback() function to be called when connection with Grandeur // is made/broken. myProject.onConnection(connectionCallback); } @@ -95,14 +95,13 @@ void setupWiFi(void) { void connectionCallback(bool status) { switch(status) { case CONNECTED: - // On successful connection with the cloud, we initialize the device's *state*. - // To do that, we get device parms from the cloud and set the *state pin* to the - // value of *state* in those parms. - Serial.println("Device is connected to the cloud."); + // On successful connection with Grandeur, we initialize the device's *state*. + // To do that, we set the *state pin* to the value of *state* from Grandeur. + Serial.println("Device is connected with Grandeur."); Serial.println("Logging voltage to Grandeur..."); break; case DISCONNECTED: - Serial.println("Device is disconnected from the cloud."); + Serial.println("Device's connection with Grandeur is broken."); break; } } diff --git a/examples/Datastore/Logging/Logging-esp8266/Logging-esp8266.ino b/examples/Datastore/Logging/Logging-esp8266/Logging-esp8266.ino index 7e2f382..f0df605 100644 --- a/examples/Datastore/Logging/Logging-esp8266/Logging-esp8266.ino +++ b/examples/Datastore/Logging/Logging-esp8266/Logging-esp8266.ino @@ -43,7 +43,7 @@ void setup() { myProject = grandeur.init(apiKey, token); // Getting object of Datastore class. myDatastore = myProject.datastore(); - // This schedules the connectionCallback() function to be called when connection with the cloud + // This schedules the connectionCallback() function to be called when connection with Grandeur // is made/broken. myProject.onConnection(connectionCallback); } @@ -89,14 +89,13 @@ void setupWiFi(void) { void connectionCallback(bool status) { switch(status) { case CONNECTED: - // On successful connection with the cloud, we initialize the device's *state*. - // To do that, we get device parms from the cloud and set the *state pin* to the - // value of *state* in those parms. - Serial.println("Device is connected to the cloud."); + // On successful connection with Grandeur, we initialize the device's *state*. + // To do that, we set the *state pin* to the value of *state* from Grandeur. + Serial.println("Device is connected with Grandeur."); Serial.println("Logging voltage to Grandeur..."); break; case DISCONNECTED: - Serial.println("Device is disconnected from the cloud."); + Serial.println("Device's connection with Grandeur is broken."); break; } } diff --git a/examples/Datastore/Searching/Searching-esp32/Searching-esp32.ino b/examples/Datastore/Searching/Searching-esp32/Searching-esp32.ino index 2102252..b4af928 100644 --- a/examples/Datastore/Searching/Searching-esp32/Searching-esp32.ino +++ b/examples/Datastore/Searching/Searching-esp32/Searching-esp32.ino @@ -42,7 +42,7 @@ void setup() { myProject = grandeur.init(apiKey, token); // Getting object of Datastore class. myDatastore = myProject.datastore(); - // This schedules the connectionCallback() function to be called when connection with the cloud + // This schedules the connectionCallback() function to be called when connection with Grandeur // is made/broken. myProject.onConnection(connectionCallback); } @@ -96,14 +96,13 @@ void setupWiFi(void) { void connectionCallback(bool status) { switch(status) { case CONNECTED: - // On successful connection with the cloud, we initialize the device's *state*. - // To do that, we get device parms from the cloud and set the *state pin* to the - // value of *state* in those parms. - Serial.println("Device is connected to the cloud."); - Serial.println("Fetching documents from Grandeur..."); + // On successful connection with Grandeur, we initialize the device's *state*. + // To do that, we set the *state pin* to the value of *state* from Grandeur. + Serial.println("Device is connected with Grandeur."); + Serial.println("Logging voltage to Grandeur..."); break; case DISCONNECTED: - Serial.println("Device is disconnected from the cloud."); + Serial.println("Device's connection with Grandeur is broken."); break; } } diff --git a/examples/Datastore/Searching/Searching-esp8266/Searching-esp8266.ino b/examples/Datastore/Searching/Searching-esp8266/Searching-esp8266.ino index 18634b2..c476655 100644 --- a/examples/Datastore/Searching/Searching-esp8266/Searching-esp8266.ino +++ b/examples/Datastore/Searching/Searching-esp8266/Searching-esp8266.ino @@ -43,7 +43,7 @@ void setup() { myProject = grandeur.init(apiKey, token); // Getting object of Datastore class. myDatastore = myProject.datastore(); - // This schedules the connectionCallback() function to be called when connection with the cloud + // This schedules the connectionCallback() function to be called when connection with Grandeur // is made/broken. myProject.onConnection(connectionCallback); } @@ -88,14 +88,13 @@ void setupWiFi(void) { void connectionCallback(bool status) { switch(status) { case CONNECTED: - // On successful connection with the cloud, we initialize the device's *state*. - // To do that, we get device parms from the cloud and set the *state pin* to the - // value of *state* in those parms. - Serial.println("Device is connected to the cloud."); - Serial.println("Fetching documents from Grandeur..."); + // On successful connection with Grandeur, we initialize the device's *state*. + // To do that, we set the *state pin* to the value of *state* from Grandeur. + Serial.println("Device is connected with Grandeur."); + Serial.println("Logging voltage to Grandeur..."); break; case DISCONNECTED: - Serial.println("Device is disconnected from the cloud."); + Serial.println("Device's connection with Grandeur is broken."); break; } } From b61beea56df8a4b1bd0a48905fb86eca9171a10b Mon Sep 17 00:00:00 2001 From: Moiz Husnain Date: Sun, 31 Jan 2021 02:37:48 +0500 Subject: [PATCH 11/11] Reverted the url to api.grandeur.tech The url in macro was trex.dev.grandeur.tech so i got to revert t. --- src/grandeurmacros.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/grandeurmacros.h b/src/grandeurmacros.h index 9d824ad..82361d8 100644 --- a/src/grandeurmacros.h +++ b/src/grandeurmacros.h @@ -9,7 +9,7 @@ */ // Connection macros -#define GRANDEUR_URL "trex.dev.api.grandeur.tech" +#define GRANDEUR_URL "api.grandeur.tech" #define GRANDEUR_PORT 443 #define GRANDEUR_FINGERPRINT ""