From 7b3b3e770d94a19b278439141466c23a68e8f576 Mon Sep 17 00:00:00 2001 From: hrithik098 Date: Wed, 7 Dec 2022 18:04:55 +0530 Subject: [PATCH 1/4] refactor: added support to add type of the thing `@type` property that will exist at root of the Thing Description as mentioned in schema --- src/ThingDevice.h | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/ThingDevice.h b/src/ThingDevice.h index f652b96..22614e9 100644 --- a/src/ThingDevice.h +++ b/src/ThingDevice.h @@ -8,15 +8,16 @@ class ThingDevice { public: String id; + const char **type; ThingDevice *next = nullptr; ThingProperty *firstProperty = nullptr; - ThingDevice(const char *_id) - : id(_id) {} + ThingDevice(const char *_id, const char **_type) + : id(_id), type(_type) {} /* * @brief Find a property with the given id - * @param TinyProperty *property + * @param {String} id : property id * @return TinyProperty *property */ ThingProperty *findProperty(const char *id) @@ -33,7 +34,7 @@ class ThingDevice /* * @brief Add a property to the thing - * @param TinyProperty *property + * @param {TinyProperty} property */ void addProperty(ThingProperty *property) { @@ -41,10 +42,10 @@ class ThingDevice firstProperty = property; } - /* + /* * @brief Set a property value - * @param {String} id - * @param {JsonVariant} newValue + * @param {String} id : property id + * @param {JsonVariant} newValue : new value of the property (boolean, number, integer, string) */ void setProperty(const char *name, const JsonVariant &newValue) { @@ -94,13 +95,22 @@ class ThingDevice /* * @brief Serialize the thing to JSON - * @param {JsonObject} descr - * @param {String} tunnelUrl + * @param {JsonObject} descr : JSON object to serialize to */ void serialize(JsonObject descr) { descr["id"] = this->id; ThingProperty *property = this->firstProperty; + descr["@context"] = "https://webthings.io/schemas"; + + JsonArray typeJson = descr.createNestedArray("@type"); + const char **type = this->type; + while ((*type) != nullptr) + { + typeJson.add(*type); + type++; + } + if (property != nullptr) { JsonObject properties = descr.createNestedObject("properties"); From b1f9e6ffc6513beb68cd0f824c1c82264e060801 Mon Sep 17 00:00:00 2001 From: hrithik098 Date: Wed, 7 Dec 2022 18:05:33 +0530 Subject: [PATCH 2/4] refactor: added flag to enable/disable logging --- src/TinyAdapter.h | 58 +++++++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/src/TinyAdapter.h b/src/TinyAdapter.h index d5bb9f3..985f976 100644 --- a/src/TinyAdapter.h +++ b/src/TinyAdapter.h @@ -4,13 +4,27 @@ #include "Thing.h" #include -#define QA_LOG(...) Serial.printf(__VA_ARGS__) +// check if logging is enabled +#ifndef TA_LOGGING +#define TA_LOG(...) (void)0 +#else +#define TA_LOG(...) Serial.printf(__VA_ARGS__) +#endif #define ARDUINOJSON_USE_LONG_LONG 1 +#ifndef LARGE_JSON_DOCUMENT_SIZE #define LARGE_JSON_DOCUMENT_SIZE 2048 +#endif + +#ifndef SMALL_JSON_DOCUMENT_SIZE #define SMALL_JSON_DOCUMENT_SIZE 512 +#endif + +#ifndef TINY_JSON_DOCUMENT_SIZE #define TINY_JSON_DOCUMENT_SIZE 256 +#endif + class TinyAdapter { @@ -53,7 +67,7 @@ class TinyAdapter DeserializationError error = deserializeJson(doc, payload); if (error) { - QA_LOG("[QA:messageHandler] deserializeJson() failed: %s\n", error.c_str()); + TA_LOG("[TA:messageHandler] deserializeJson() failed: %s\n", error.c_str()); String msg = "{\"messageType\":\"error\", \"errorMessage\":\"deserializeJson() failed \"}"; sendMessage(msg); } @@ -62,14 +76,14 @@ class TinyAdapter if (root["messageType"] == "getProperty") { - QA_LOG("[QA:messageHandler] Received a 'getProperty' message\n"); + TA_LOG("[TA:messageHandler] Received a 'getProperty' message\n"); String thingId = root["thingId"]; getProperties(thingId); } else if (root["messageType"] == "setProperty") { - QA_LOG("[QA:messageHandler] Received a 'setProperty' message\n"); + TA_LOG("[TA:messageHandler] Received a 'setProperty' message\n"); String thingId = root["thingId"]; String propertyId = root["data"]["propertyId"]; String data = root["data"]; @@ -78,13 +92,13 @@ class TinyAdapter else if (root["messageType"] == "getAllThings") { - QA_LOG("[QA:messageHandler] Received a 'getAllThings' message\n"); + TA_LOG("[TA:messageHandler] Received a 'getAllThings' message\n"); getThingDescription(); } else { - QA_LOG("[QA:messageHandler] Unknown message type received. Payload: %s\n", payload.c_str()); + TA_LOG("[TA:messageHandler] Unknown message type received. Payload: %s\n", payload.c_str()); } } @@ -96,17 +110,17 @@ class TinyAdapter switch (type) { case WStype_DISCONNECTED: - QA_LOG("[QA:webSocketEvent] Disconnect!\n"); + TA_LOG("[TA:webSocketEvent] Disconnect!\n"); break; case WStype_CONNECTED: - QA_LOG("[QA:webSocketEvent] Connected to tunnel server!\n"); + TA_LOG("[TA:webSocketEvent] Connected to tunnel server!\n"); webSocket.sendTXT("{\"messageType\":\"StartWs\"}"); break; case WStype_TEXT: { - QA_LOG("[QA:payloadHandler] New message received!\n"); + TA_LOG("[TA:payloadHandler] New message received!\n"); char msgch[length]; for (unsigned int i = 0; i < length; i++) { @@ -119,31 +133,31 @@ class TinyAdapter } case WStype_ERROR: - QA_LOG("[QA:webSocketEvent] Error!\n"); + TA_LOG("[TA:webSocketEvent] Error!\n"); break; case WStype_FRAGMENT_TEXT_START: - QA_LOG("[QA:webSocketEvent] Fragment Text Start!\n"); + TA_LOG("[TA:webSocketEvent] Fragment Text Start!\n"); break; case WStype_FRAGMENT_BIN_START: - QA_LOG("[QA:webSocketEvent] Fragment Bin Start!\n"); + TA_LOG("[TA:webSocketEvent] Fragment Bin Start!\n"); break; case WStype_FRAGMENT: - QA_LOG("[QA:webSocketEvent] Fragment!\n"); + TA_LOG("[TA:webSocketEvent] Fragment!\n"); break; case WStype_FRAGMENT_FIN: - QA_LOG("[QA:webSocketEvent] Fragment Fin!\n"); + TA_LOG("[TA:webSocketEvent] Fragment Fin!\n"); break; case WStype_PING: - QA_LOG("[QA:webSocketEvent] Ping!\n"); + TA_LOG("[TA:webSocketEvent] Ping!\n"); break; case WStype_PONG: - QA_LOG("[QA:webSocketEvent] Pong!\n"); + TA_LOG("[TA:webSocketEvent] Pong!\n"); break; } } @@ -337,7 +351,7 @@ class TinyAdapter String jsonStr; serializeJson(finalProp, jsonStr); sendMessage(jsonStr); - QA_LOG("[QA:getProperties] Property data was sent back.\n"); + TA_LOG("[TA:getProperties] Property data was sent back.\n"); } /* @@ -353,13 +367,13 @@ class TinyAdapter ThingDevice *device = findDeviceById(thingId); if (device == nullptr) { - QA_LOG("[QA:setProperty] Thing not found. %s \n", thingId.c_str()); + TA_LOG("[TA:setProperty] Thing not found. %s \n", thingId.c_str()); return; } ThingProperty *property = findPropertyById(device, propertyId); if (property == nullptr) { - QA_LOG("[QA:setProperty] Property not found. %s \n", propertyId.c_str()); + TA_LOG("[TA:setProperty] Property not found. %s \n", propertyId.c_str()); return; } @@ -368,15 +382,15 @@ class TinyAdapter if (error) { - QA_LOG("[QA:setProperty] Parsing json error. %s \n", error.c_str()); + TA_LOG("[TA:setProperty] Parsing json error. %s \n", error.c_str()); return; } - QA_LOG("[QA:setProperty] Property data was received. %s \n", newPropertyData.c_str()); + TA_LOG("[TA:setProperty] Property data was received. %s \n", newPropertyData.c_str()); JsonObject newProp = newBuffer.as(); device->setProperty(property->id.c_str(), newProp["value"]); // Don't send the value back to the server // The update method will send the changed properties - QA_LOG("[QA:setProperty] Property value has been set! \n"); + TA_LOG("[TA:setProperty] Property value has been set! \n"); } }; From f5ca7fe6e6d193028f07770a68718f047c95af76 Mon Sep 17 00:00:00 2001 From: hrithik098 Date: Wed, 7 Dec 2022 18:06:09 +0530 Subject: [PATCH 3/4] docs: Updated readme, comments, example with new changes --- README.md | 68 ++++++++++++++++++++++++++---------- examples/simple/src/main.cpp | 5 ++- src/ThingProperty.h | 14 ++++---- 3 files changed, 59 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 60c4b77..9afb731 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # tiny-webthing -A tiny Web Thing implementation for Arduino. This is library does not support events and actions. The library uses websocket for communication. So you have to create a websocket server to be able to communicate. +A simple library for the ESP8266 that implements Mozilla's proposed Web of Things API. This library is a port of [webthing-arduino](https://github.com/WebThingsIO/webthing-arduino) but this library is much smaller and simpler. Instead of creating a server on the ESP8266 and communicate locally, this library uses websocket to tunnel the ESP8266/thing and communicate with it over the internet. So to use this library you need to write a tunnel server that will communicate with the ESP8266/thing over websocket with following schema as mentioned below. ## Installation (Platformio) @@ -114,23 +114,6 @@ response : } ``` -## Architecture - -![Architecture](https://img.shields.io/badge/Architecture-Tiny%20Things-blue.svg) - -![Architecture](/docs/tiny-webthing-arch.png) - -## TODO - -- [x] Use StaticJsonDocument instead of DynamicJsonDocument -- [ ] Remove dependency on ArduinoJson -- [ ] Reduce size of TD -- [ ] Fixed size of messages received from server -- [ ] Change message schema in tunnel server and client - - - - ## Example ```C++ @@ -146,7 +129,10 @@ const int ledPin = LED_BUILTIN; TinyAdapter *adapter; void onOffChanged(ThingPropertyValue newValue); -ThingDevice led("tiny-thing-02"); + +// Define the types of the thing. This will be `@type` in the thing description. +const char *ledTypes[] = {"OnOffSwitch", "LightBrightnesControl", nullptr}; +ThingDevice led("tiny-thing-02", ledTypes); ThingProperty ledOn("on", BOOLEAN, "OnOffProperty", onOffChanged); ThingProperty ledBrightness("brightness", NUMBER, "BrightnessProperty", nullptr); @@ -201,3 +187,47 @@ void loop() ``` + + +## Configuration +If you have a complex device with large thing descriptions, you may need to increase the size of the JSON buffers. The buffer sizes are configurable as such: + +```cpp +// By default, buffers are 256 for tiny, 512 bytes for small documents, 2048 for larger ones +// You can change these by defining them before including the library +#define LARGE_JSON_DOCUMENT_SIZE 2048 +#define SMALL_JSON_DOCUMENT_SIZE 512 +#define TINY_JSON_DOCUMENT_SIZE 256 + +#include +#include + +``` + +- Enable debug mode by defining `TA_LOGGING` before including the library. + +```cpp +#define TA_LOGGING 1 + +#include +#include + +``` + + +## Architecture + +![Architecture](https://img.shields.io/badge/Architecture-Tiny%20Things-blue.svg) + +![Architecture](/docs/tiny-webthing-arch.png) + +## TODO + +- [x] Use StaticJsonDocument instead of DynamicJsonDocument +- [ ] Remove dependency on ArduinoJson +- [ ] Reduce size of TD +- [ ] Fixed size of messages received from server +- [ ] Change message schema in tunnel server and client +- [ ] Add support for actions, events + + diff --git a/examples/simple/src/main.cpp b/examples/simple/src/main.cpp index 8a11fc9..c41bb14 100644 --- a/examples/simple/src/main.cpp +++ b/examples/simple/src/main.cpp @@ -10,7 +10,10 @@ const int ledPin = LED_BUILTIN; TinyAdapter *adapter; void onOffChanged(ThingPropertyValue newValue); -ThingDevice led("tiny-thing-02"); + +// Define the types of the thing. This will be `@type` in the thing description. +const char *ledTypes[] = {"OnOffSwitch", "LightBrightnesControl", nullptr}; +ThingDevice led("tiny-thing-02", ledTypes); ThingProperty ledOn("on", BOOLEAN, "OnOffProperty", onOffChanged); ThingProperty ledBrightness("brightness", NUMBER, "BrightnessProperty", nullptr); diff --git a/src/ThingProperty.h b/src/ThingProperty.h index 45849c2..574ba88 100644 --- a/src/ThingProperty.h +++ b/src/ThingProperty.h @@ -43,7 +43,7 @@ class ThingItem /* * @brief Set the value of the property - * @param TinyDataValue value + * @param TinyDataValue value : {boolean, number, integer, string} */ void setValue(ThingDataValue newValue) { @@ -53,7 +53,7 @@ class ThingItem /* * @brief Set the value of the property - * @param const char *s + * @param const char *s : string value */ void setValue(const char *s) { @@ -81,8 +81,7 @@ class ThingItem /* * @brief Serialize the property to JSON * @param JsonObject &json - * @param String thingId - * @param String resourceType + * @param String deviceId * @example * { * "id": "temperature", @@ -173,9 +172,8 @@ class ThingProperty : public ThingItem /* * @brief Serialize the property to JSON - * @param JsonObject obj - * @param String thingId - * @param String resourceType + * @param JsonObject obj : JSON object to serialize to + * @param String deviceId : ID of the thing */ void serialize(JsonObject obj, String deviceId) { @@ -199,7 +197,7 @@ class ThingProperty : public ThingItem /* * @brief If the property has changed, call the callback function * if it exists. - * @param TinyDataValue value + * @param TinyDataValue value : {boolean, number, integer, string} */ void changed(ThingPropertyValue newValue) { From b7aecf2fbd9d82e4986f0bf5967948507ec751e7 Mon Sep 17 00:00:00 2001 From: hrithik098 Date: Wed, 7 Dec 2022 18:06:28 +0530 Subject: [PATCH 4/4] version bump 0.1.1 --- library.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.json b/library.json index 030ecc2..01b041f 100644 --- a/library.json +++ b/library.json @@ -2,7 +2,7 @@ "name": "tiny-webthing", "description": "A library for creating Tiny Web Things. This library does not support actions and events.", "keywords": "Communication", - "version": "0.1.0", + "version": "0.1.1", "authors": { "name": "Hrithik", "email": "hrithiky328@gmail.com",