From b06feaf3e0953820e8c0e23d3779a433b3e6d107 Mon Sep 17 00:00:00 2001 From: Kirill Shumilov Date: Thu, 11 Jun 2020 11:43:58 +0300 Subject: [PATCH 01/10] fix(stdlib): fix sending of the last row of a request in tethering-inet --- workspace/__lib__/xod/debug/tethering-inet/patch.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/workspace/__lib__/xod/debug/tethering-inet/patch.cpp b/workspace/__lib__/xod/debug/tethering-inet/patch.cpp index 3f9e4fb10..d8dab6cc3 100644 --- a/workspace/__lib__/xod/debug/tethering-inet/patch.cpp +++ b/workspace/__lib__/xod/debug/tethering-inet/patch.cpp @@ -217,6 +217,10 @@ class TetheringInternet { _serial->print((char)*it); } } + // Ensure the latest line of request sent + if (!nextLine) { + _serial->println(); + } _serial->flush(); From 6f3ce9baff02b87f0f5093071c0797987aaf68f3 Mon Sep 17 00:00:00 2001 From: Kirill Shumilov Date: Thu, 11 Jun 2020 11:44:33 +0300 Subject: [PATCH 02/10] fix(xod-client-electron): fix cutting the latest symbol of the response in tethering-inet --- .../xod-client-electron/src/debugger/tetheringInetMiddleware.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xod-client-electron/src/debugger/tetheringInetMiddleware.js b/packages/xod-client-electron/src/debugger/tetheringInetMiddleware.js index 665d16de5..f4c5ccff3 100644 --- a/packages/xod-client-electron/src/debugger/tetheringInetMiddleware.js +++ b/packages/xod-client-electron/src/debugger/tetheringInetMiddleware.js @@ -46,7 +46,7 @@ const splitDataOnChunks = R.curry((maxChunkSize, nodeId, data) => { R.compose( R.map(formatChunk), R.splitEvery(dataMaxLength), - R.slice(R.__, -1, data), + R.slice(R.__, data.length, data), R.add(1), R.indexOf(':') ), From 6d0ca8eff7422bc8729b87e404c471de8d5df4c3 Mon Sep 17 00:00:00 2001 From: Kirill Shumilov Date: Thu, 11 Jun 2020 11:48:49 +0300 Subject: [PATCH 03/10] feat(stdlib): add datetime constructor and destructor from/to POSIX time --- .../__lib__/xod/datetime/from-posix/patch.cpp | 14 ++++ .../xod/datetime/from-posix/patch.xodp | 65 +++++++++++++++++++ .../__lib__/xod/datetime/to-posix/patch.cpp | 17 +++++ .../__lib__/xod/datetime/to-posix/patch.xodp | 65 +++++++++++++++++++ 4 files changed, 161 insertions(+) create mode 100644 workspace/__lib__/xod/datetime/from-posix/patch.cpp create mode 100644 workspace/__lib__/xod/datetime/from-posix/patch.xodp create mode 100644 workspace/__lib__/xod/datetime/to-posix/patch.cpp create mode 100644 workspace/__lib__/xod/datetime/to-posix/patch.xodp diff --git a/workspace/__lib__/xod/datetime/from-posix/patch.cpp b/workspace/__lib__/xod/datetime/from-posix/patch.cpp new file mode 100644 index 000000000..a541e804f --- /dev/null +++ b/workspace/__lib__/xod/datetime/from-posix/patch.cpp @@ -0,0 +1,14 @@ + +struct State { +}; + +{{ GENERATED_CODE }} + +void evaluate(Context ctx) { + uint32_t b3 = getValue(ctx); + uint32_t b2 = getValue(ctx); + uint32_t b1 = getValue(ctx); + uint32_t b0 = getValue(ctx); + uint32_t posix = ((b3 << 24) | (b2 << 16) | (b1 << 8) | b0); + emitValue(ctx, (ValueType::T) posix); +} diff --git a/workspace/__lib__/xod/datetime/from-posix/patch.xodp b/workspace/__lib__/xod/datetime/from-posix/patch.xodp new file mode 100644 index 000000000..0e5eb9062 --- /dev/null +++ b/workspace/__lib__/xod/datetime/from-posix/patch.xodp @@ -0,0 +1,65 @@ +{ + "description": "Constructs a datetime value from a POSIX time format represented as 4 bytes.", + "nodes": [ + { + "description": "Most significant byte", + "id": "HJbV2vdL3I", + "label": "B3", + "position": { + "units": "slots", + "x": 0, + "y": 0 + }, + "type": "xod/patch-nodes/input-byte" + }, + { + "id": "HJg4hvuL3L", + "label": "B2", + "position": { + "units": "slots", + "x": 1, + "y": 0 + }, + "type": "xod/patch-nodes/input-byte" + }, + { + "id": "HkNnPd8nI", + "label": "B1", + "position": { + "units": "slots", + "x": 2, + "y": 0 + }, + "type": "xod/patch-nodes/input-byte" + }, + { + "id": "SkVTPuL2I", + "position": { + "units": "slots", + "x": 0, + "y": 1 + }, + "type": "xod/patch-nodes/not-implemented-in-xod" + }, + { + "id": "rys3POU3L", + "position": { + "units": "slots", + "x": 0, + "y": 2 + }, + "type": "@/output-datetime" + }, + { + "description": "Least significant byte", + "id": "ryzE3DO83I", + "label": "B0", + "position": { + "units": "slots", + "x": 3, + "y": 0 + }, + "type": "xod/patch-nodes/input-byte" + } + ] +} diff --git a/workspace/__lib__/xod/datetime/to-posix/patch.cpp b/workspace/__lib__/xod/datetime/to-posix/patch.cpp new file mode 100644 index 000000000..791b713ed --- /dev/null +++ b/workspace/__lib__/xod/datetime/to-posix/patch.cpp @@ -0,0 +1,17 @@ + +struct State { +}; + +{{ GENERATED_CODE }} + +void evaluate(Context ctx) { + uint32_t val = (uint32_t) getValue(ctx); + uint8_t b3 = (val >> 24); + uint8_t b2 = (val >> 16); + uint8_t b1 = (val >> 8); + uint8_t b0 = val; + emitValue(ctx, b0); + emitValue(ctx, b1); + emitValue(ctx, b2); + emitValue(ctx, b3); +} diff --git a/workspace/__lib__/xod/datetime/to-posix/patch.xodp b/workspace/__lib__/xod/datetime/to-posix/patch.xodp new file mode 100644 index 000000000..544db8f53 --- /dev/null +++ b/workspace/__lib__/xod/datetime/to-posix/patch.xodp @@ -0,0 +1,65 @@ +{ + "description": "Transforms a datetime into a POSIX time format represented as 4 bytes.", + "nodes": [ + { + "id": "Bk7f_u8hU", + "label": "B2", + "position": { + "units": "slots", + "x": 1, + "y": 2 + }, + "type": "xod/patch-nodes/output-byte" + }, + { + "id": "S1jzu_83I", + "position": { + "units": "slots", + "x": 0, + "y": 1 + }, + "type": "xod/patch-nodes/not-implemented-in-xod" + }, + { + "description": "Most significant byte", + "id": "rJbXzOuLhI", + "label": "B3", + "position": { + "units": "slots", + "x": 0, + "y": 2 + }, + "type": "xod/patch-nodes/output-byte" + }, + { + "description": "Least significant byte", + "id": "rkMQzOuLnI", + "label": "B0", + "position": { + "units": "slots", + "x": 3, + "y": 2 + }, + "type": "xod/patch-nodes/output-byte" + }, + { + "id": "rkdf_uI2U", + "position": { + "units": "slots", + "x": 0, + "y": 0 + }, + "type": "@/input-datetime" + }, + { + "id": "ryemGddU28", + "label": "B1", + "position": { + "units": "slots", + "x": 2, + "y": 2 + }, + "type": "xod/patch-nodes/output-byte" + } + ] +} From 629399d5b5a16dd22dd683f61f0ef258005623a9 Mon Sep 17 00:00:00 2001 From: Kirill Shumilov Date: Thu, 11 Jun 2020 11:49:23 +0300 Subject: [PATCH 04/10] feat(stdlib): add `parse-u32` and `parse-number` (float) nodes to `xod/stream` library --- .../__lib__/xod/stream/parse-number/patch.cpp | 47 ++++++++ .../xod/stream/parse-number/patch.xodp | 69 ++++++++++++ .../__lib__/xod/stream/parse-u32/patch.cpp | 36 +++++++ .../__lib__/xod/stream/parse-u32/patch.xodp | 100 ++++++++++++++++++ 4 files changed, 252 insertions(+) create mode 100644 workspace/__lib__/xod/stream/parse-number/patch.cpp create mode 100644 workspace/__lib__/xod/stream/parse-number/patch.xodp create mode 100644 workspace/__lib__/xod/stream/parse-u32/patch.cpp create mode 100644 workspace/__lib__/xod/stream/parse-u32/patch.xodp diff --git a/workspace/__lib__/xod/stream/parse-number/patch.cpp b/workspace/__lib__/xod/stream/parse-number/patch.cpp new file mode 100644 index 000000000..c22457d7b --- /dev/null +++ b/workspace/__lib__/xod/stream/parse-number/patch.cpp @@ -0,0 +1,47 @@ + +struct State { + Number n = 0; + Number fraction = 1.0; + bool isNegative = false; + bool isFraction = false; + + bool isDone = false; +}; + +{{ GENERATED_CODE }} + +void evaluate(Context ctx) { + auto state = getState(ctx); + + if (isInputDirty(ctx)) { + state->isDone = false; + state->n = 0; + } + + if (!isInputDirty(ctx) || state->isDone) + return; + + auto c = getValue(ctx); + + bool isFraction = false; + bool isNegative = false; + Number fraction = 1.0; + + if (c == '-' && state->n == 0) { + state->isNegative = true; + } else if (c == '.' && !state->isFraction) { + state->isFraction = true; + } else if (c >= '0' && c <= '9') { + state->n *= 10; + state->n += c - '0'; + if (state->isFraction) { + state->fraction *= 0.1; + } + } else { + state->isDone = true; + emitValue(ctx, 1); + } + + Number sign = state->isNegative ? -1 : 1; + emitValue(ctx, sign * state->n * state->fraction); +} diff --git a/workspace/__lib__/xod/stream/parse-number/patch.xodp b/workspace/__lib__/xod/stream/parse-number/patch.xodp new file mode 100644 index 000000000..04f041a71 --- /dev/null +++ b/workspace/__lib__/xod/stream/parse-number/patch.xodp @@ -0,0 +1,69 @@ +{ + "description": "Read a number with floating point from a stream of characters. Stop when a non-numeric character was encountered", + "nodes": [ + { + "description": "The next character to be processed", + "id": "ByEaDQKC3I", + "label": "CHAR", + "position": { + "units": "slots", + "x": 0, + "y": 0 + }, + "type": "xod/patch-nodes/input-byte" + }, + { + "description": "Push a new character to process", + "id": "Byfpw7FCnU", + "label": "PUSH", + "position": { + "units": "slots", + "x": 3, + "y": 0 + }, + "type": "xod/patch-nodes/input-pulse" + }, + { + "description": "Reset the parsed number to 0 and start over", + "id": "Bymaw7FAhL", + "label": "RST", + "position": { + "units": "slots", + "x": 6, + "y": 0 + }, + "type": "xod/patch-nodes/input-pulse" + }, + { + "id": "H1xTwXF0nU", + "position": { + "units": "slots", + "x": 0, + "y": 1 + }, + "type": "xod/patch-nodes/not-implemented-in-xod" + }, + { + "description": "The resulting integer", + "id": "Sk-6vQKRnL", + "label": "NUM", + "position": { + "units": "slots", + "x": 0, + "y": 2 + }, + "type": "xod/patch-nodes/output-number" + }, + { + "description": "Pulses when the non-numerical character was encountered", + "id": "rkawmFR3I", + "label": "END", + "position": { + "units": "slots", + "x": 3, + "y": 2 + }, + "type": "xod/patch-nodes/output-pulse" + } + ] +} diff --git a/workspace/__lib__/xod/stream/parse-u32/patch.cpp b/workspace/__lib__/xod/stream/parse-u32/patch.cpp new file mode 100644 index 000000000..7cf2f25af --- /dev/null +++ b/workspace/__lib__/xod/stream/parse-u32/patch.cpp @@ -0,0 +1,36 @@ +struct State { + uint32_t n = 0; + bool isDone = false; +}; + +{{ GENERATED_CODE }} + +void evaluate(Context ctx) { + auto state = getState(ctx); + + if (isInputDirty(ctx)) { + state->isDone = false; + state->n = 0; + } + + if (!isInputDirty(ctx) || state->isDone) + return; + + auto c = getValue(ctx); + if (c >= '0' && c <= '9') { + state->n *= 10; + state->n += c - '0'; + } else { + state->isDone = true; + emitValue(ctx, 1); + } + + uint8_t b3 = (state->n >> 24); + uint8_t b2 = (state->n >> 16); + uint8_t b1 = (state->n >> 8); + uint8_t b0 = state->n; + emitValue(ctx, b0); + emitValue(ctx, b1); + emitValue(ctx, b2); + emitValue(ctx, b3); +} diff --git a/workspace/__lib__/xod/stream/parse-u32/patch.xodp b/workspace/__lib__/xod/stream/parse-u32/patch.xodp new file mode 100644 index 000000000..7375a34d3 --- /dev/null +++ b/workspace/__lib__/xod/stream/parse-u32/patch.xodp @@ -0,0 +1,100 @@ +{ + "description": "Read an unsigned integer number from a stream of characters and returns it as 4 bytes. Stop when a non-numeric character was encountered", + "nodes": [ + { + "description": "Least significant byte", + "id": "B1GszSOU38", + "label": "B0", + "position": { + "units": "slots", + "x": 3, + "y": 2 + }, + "type": "xod/patch-nodes/output-byte" + }, + { + "description": "Pulses when the non-numerical character was encountered", + "id": "BJTWS_Lh8", + "label": "END", + "position": { + "units": "slots", + "x": 6, + "y": 2 + }, + "type": "xod/patch-nodes/output-pulse" + }, + { + "id": "ByeifH_82L", + "label": "B1", + "position": { + "units": "slots", + "x": 2, + "y": 2 + }, + "type": "xod/patch-nodes/output-byte" + }, + { + "description": "Push a new character to process", + "id": "H1faWHuInL", + "label": "PUSH", + "position": { + "units": "slots", + "x": 3, + "y": 0 + }, + "type": "xod/patch-nodes/input-pulse" + }, + { + "description": "Most significant byte", + "id": "HJWjGBdIhL", + "label": "B3", + "position": { + "units": "slots", + "x": 0, + "y": 2 + }, + "type": "xod/patch-nodes/output-byte" + }, + { + "description": "Reset the parsed unsigned integer to 0 and start over", + "id": "HympbBOLh8", + "label": "RST", + "position": { + "units": "slots", + "x": 6, + "y": 0 + }, + "type": "xod/patch-nodes/input-pulse" + }, + { + "id": "SkofSOLh8", + "label": "B2", + "position": { + "units": "slots", + "x": 1, + "y": 2 + }, + "type": "xod/patch-nodes/output-byte" + }, + { + "id": "rkxa-SOUh8", + "position": { + "units": "slots", + "x": 0, + "y": 1 + }, + "type": "xod/patch-nodes/not-implemented-in-xod" + }, + { + "description": "The next character to be processed", + "id": "ryNpbr_L3U", + "label": "CHAR", + "position": { + "units": "slots", + "x": 0, + "y": 0 + }, + "type": "xod/patch-nodes/input-byte" + } + ] +} From dc130932fef75106f822275e05320da5afbe3236 Mon Sep 17 00:00:00 2001 From: Kirill Shumilov Date: Thu, 11 Jun 2020 11:49:46 +0300 Subject: [PATCH 05/10] feat(stdlib): add a brand-new `xod-cloud/basics` library --- .../basics/example-external-ip/patch.xodp | 80 ++++ .../basics/example-now-iso/patch.xodp | 80 ++++ .../xod-cloud/basics/example-now/patch.xodp | 103 +++++ .../xod-cloud/basics/external-ip/patch.xodp | 277 ++++++++++++ .../xod-cloud/basics/now-iso/patch.xodp | 260 +++++++++++ .../__lib__/xod-cloud/basics/now/patch.xodp | 270 +++++++++++ .../__lib__/xod-cloud/basics/project.xod | 9 + .../feeds/cloud-boolean-custom/patch.xodp | 312 +++++++++++++ .../feeds/cloud-number-custom/patch.xodp | 286 ++++++++++++ .../feeds/cloud-store-custom/patch.xodp | 22 +- .../feeds/cloud-string-custom/patch.xodp | 291 ++++++++++++ .../xod-cloud/feeds/feeds-request/patch.xodp | 427 ++++++++++++++++++ 12 files changed, 2406 insertions(+), 11 deletions(-) create mode 100644 workspace/__lib__/xod-cloud/basics/example-external-ip/patch.xodp create mode 100644 workspace/__lib__/xod-cloud/basics/example-now-iso/patch.xodp create mode 100644 workspace/__lib__/xod-cloud/basics/example-now/patch.xodp create mode 100644 workspace/__lib__/xod-cloud/basics/external-ip/patch.xodp create mode 100644 workspace/__lib__/xod-cloud/basics/now-iso/patch.xodp create mode 100644 workspace/__lib__/xod-cloud/basics/now/patch.xodp create mode 100644 workspace/__lib__/xod-cloud/basics/project.xod create mode 100644 workspace/__lib__/xod-cloud/feeds/cloud-boolean-custom/patch.xodp create mode 100644 workspace/__lib__/xod-cloud/feeds/cloud-number-custom/patch.xodp create mode 100644 workspace/__lib__/xod-cloud/feeds/cloud-string-custom/patch.xodp create mode 100644 workspace/__lib__/xod-cloud/feeds/feeds-request/patch.xodp diff --git a/workspace/__lib__/xod-cloud/basics/example-external-ip/patch.xodp b/workspace/__lib__/xod-cloud/basics/example-external-ip/patch.xodp new file mode 100644 index 000000000..192a74767 --- /dev/null +++ b/workspace/__lib__/xod-cloud/basics/example-external-ip/patch.xodp @@ -0,0 +1,80 @@ +{ + "links": [ + { + "id": "BJhT-HrnU", + "input": { + "nodeId": "ByZV6-BShI", + "pinKey": "HkXK-dGob" + }, + "output": { + "nodeId": "HJtT-SSnU", + "pinKey": "Syv_rWrSn8" + } + }, + { + "id": "rJoTbrB38", + "input": { + "nodeId": "HJtT-SSnU", + "pinKey": "BJluSWHrhU" + }, + "output": { + "nodeId": "rkzVpbHr38", + "pinKey": "Bkf4BDsmV" + } + }, + { + "id": "ry5TZBS2I", + "input": { + "nodeId": "HJtT-SSnU", + "pinKey": "B1OS-rS3I" + }, + "output": { + "nodeId": "SJx4pbHrn8", + "pinKey": "SyveJHHBL" + } + } + ], + "nodes": [ + { + "id": "ByZV6-BShI", + "position": { + "units": "slots", + "x": 1, + "y": 2 + }, + "size": { + "height": 1, + "units": "slots", + "width": 4 + }, + "type": "xod/debug/watch" + }, + { + "id": "HJtT-SSnU", + "position": { + "units": "slots", + "x": 1, + "y": 1 + }, + "type": "@/external-ip" + }, + { + "id": "SJx4pbHrn8", + "position": { + "units": "slots", + "x": 1, + "y": 0 + }, + "type": "xod/debug/tethering-inet" + }, + { + "id": "rkzVpbHr38", + "position": { + "units": "slots", + "x": 2, + "y": 0 + }, + "type": "xod/debug/tweak-pulse" + } + ] +} diff --git a/workspace/__lib__/xod-cloud/basics/example-now-iso/patch.xodp b/workspace/__lib__/xod-cloud/basics/example-now-iso/patch.xodp new file mode 100644 index 000000000..ebf5d40aa --- /dev/null +++ b/workspace/__lib__/xod-cloud/basics/example-now-iso/patch.xodp @@ -0,0 +1,80 @@ +{ + "links": [ + { + "id": "B1G_6NBnI", + "input": { + "nodeId": "ryZupVrn8", + "pinKey": "Sywf6EBhU" + }, + "output": { + "nodeId": "SkghDaVShL", + "pinKey": "SyveJHHBL" + } + }, + { + "id": "H1mO64S38", + "input": { + "nodeId": "ryZupVrn8", + "pinKey": "rJlwfT4r2I" + }, + "output": { + "nodeId": "Bkm3w6Vr3I", + "pinKey": "Bkf4BDsmV" + } + }, + { + "id": "ry4uTErnI", + "input": { + "nodeId": "SkM3va4BhI", + "pinKey": "HkXK-dGob" + }, + "output": { + "nodeId": "ryZupVrn8", + "pinKey": "r1jBTESnU" + } + } + ], + "nodes": [ + { + "id": "Bkm3w6Vr3I", + "position": { + "units": "slots", + "x": 4, + "y": 0 + }, + "type": "xod/debug/tweak-pulse" + }, + { + "id": "SkM3va4BhI", + "position": { + "units": "slots", + "x": 3, + "y": 2 + }, + "size": { + "height": 1, + "units": "slots", + "width": 4 + }, + "type": "xod/debug/watch" + }, + { + "id": "SkghDaVShL", + "position": { + "units": "slots", + "x": 3, + "y": 0 + }, + "type": "xod/debug/tethering-inet" + }, + { + "id": "ryZupVrn8", + "position": { + "units": "slots", + "x": 3, + "y": 1 + }, + "type": "@/now-iso" + } + ] +} diff --git a/workspace/__lib__/xod-cloud/basics/example-now/patch.xodp b/workspace/__lib__/xod-cloud/basics/example-now/patch.xodp new file mode 100644 index 000000000..907937caf --- /dev/null +++ b/workspace/__lib__/xod-cloud/basics/example-now/patch.xodp @@ -0,0 +1,103 @@ +{ + "links": [ + { + "id": "B17fLq838", + "input": { + "nodeId": "HyFcVVrnI", + "pinKey": "Hy_D4G0JOX" + }, + "output": { + "nodeId": "Hk0-UcL3L", + "pinKey": "ryFe8qI3U" + } + }, + { + "id": "ByA9NES2L", + "input": { + "nodeId": "HJicVES38", + "pinKey": "HkXK-dGob" + }, + "output": { + "nodeId": "HyFcVVrnI", + "pinKey": "BkvDEzR1Om" + } + }, + { + "id": "SkJfI9LhL", + "input": { + "nodeId": "Hk0-UcL3L", + "pinKey": "r1lFErc828" + }, + "output": { + "nodeId": "H16KVNBhL", + "pinKey": "SyveJHHBL" + } + }, + { + "id": "rJCCZq0h8", + "input": { + "nodeId": "Hk0-UcL3L", + "pinKey": "HyF4Hq828" + }, + "output": { + "nodeId": "B1nAW5C2U", + "pinKey": "Bkf4BDsmV" + } + } + ], + "nodes": [ + { + "id": "B1nAW5C2U", + "position": { + "units": "slots", + "x": 5, + "y": 1 + }, + "type": "xod/debug/tweak-pulse" + }, + { + "id": "H16KVNBhL", + "position": { + "units": "slots", + "x": 4, + "y": 1 + }, + "type": "xod/debug/tethering-inet" + }, + { + "id": "HJicVES38", + "position": { + "units": "slots", + "x": 4, + "y": 4 + }, + "size": { + "height": 1, + "units": "slots", + "width": 4 + }, + "type": "xod/debug/watch" + }, + { + "boundLiterals": { + "HyF4Hq828": "Never" + }, + "id": "Hk0-UcL3L", + "position": { + "units": "slots", + "x": 4, + "y": 2 + }, + "type": "@/now" + }, + { + "id": "HyFcVVrnI", + "position": { + "units": "slots", + "x": 4, + "y": 3 + }, + "type": "xod/datetime/format-timestamp" + } + ] +} diff --git a/workspace/__lib__/xod-cloud/basics/external-ip/patch.xodp b/workspace/__lib__/xod-cloud/basics/external-ip/patch.xodp new file mode 100644 index 000000000..aa8502a2f --- /dev/null +++ b/workspace/__lib__/xod-cloud/basics/external-ip/patch.xodp @@ -0,0 +1,277 @@ +{ + "description": "Gets an external IP using a XOD Cloud API.", + "links": [ + { + "id": "B1tuSWrSh8", + "input": { + "nodeId": "HkWOSWrB28", + "pinKey": "Bk5vjCxW7Q" + }, + "output": { + "nodeId": "B1OS-rS3I", + "pinKey": "__out__" + } + }, + { + "id": "BkldfHBnU", + "input": { + "nodeId": "rJ8drZHr2I", + "pinKey": "r1NYhRDZ7" + }, + "output": { + "nodeId": "HJ8vMrS2L", + "pinKey": "r1XBwQCWQ" + } + }, + { + "id": "By0vMrS2U", + "input": { + "nodeId": "HJ8vMrS2L", + "pinKey": "BJYbP7CZm" + }, + "output": { + "nodeId": "HkzOS-BrhL", + "pinKey": "SkSGwoAZQ" + } + }, + { + "id": "Byxx_HZrrh8", + "input": { + "nodeId": "rJ8drZHr2I", + "pinKey": "HyvKhAv-7" + }, + "output": { + "nodeId": "Hy4_HWHShU", + "pinKey": "__out__" + } + }, + { + "id": "H1WOfSrn8", + "input": { + "nodeId": "HJ8vMrS2L", + "pinKey": "r1CWwm0b7" + }, + "output": { + "nodeId": "HkzOS-BrhL", + "pinKey": "SkYZwiRbm" + } + }, + { + "id": "S1WgOr-SSnI", + "input": { + "nodeId": "Syv_rWrSn8", + "pinKey": "__in__" + }, + "output": { + "nodeId": "rJ8drZHr2I", + "pinKey": "S1s7pCDbQ" + } + }, + { + "id": "r1ourbSBhI", + "input": { + "nodeId": "HkzOS-BrhL", + "pinKey": "B18iIoA-m" + }, + "output": { + "nodeId": "HkWOSWrB28", + "pinKey": "SkDiRgZQX" + } + }, + { + "id": "r1y_MrB2U", + "input": { + "nodeId": "rJ8drZHr2I", + "pinKey": "HJi_30PZX" + }, + "output": { + "nodeId": "HJ8vMrS2L", + "pinKey": "By5Vv7C-7" + } + }, + { + "id": "rJ0_HWHB28", + "input": { + "nodeId": "B1XuB-SH3U", + "pinKey": "__in__" + }, + "output": { + "nodeId": "BJluSWHrhU", + "pinKey": "__out__" + } + }, + { + "id": "rJjo-Br3L", + "input": { + "nodeId": "S1HuBWBS2I", + "pinKey": "__in__" + }, + "output": { + "nodeId": "HkWOSWrB28", + "pinKey": "SyKDiAgbXQ" + } + }, + { + "id": "rJm_MHHhU", + "input": { + "nodeId": "HJ8vMrS2L", + "pinKey": "S1a8PX0Wm" + }, + "output": { + "nodeId": "Hy4_HWHShU", + "pinKey": "__out__" + } + }, + { + "id": "rkquBWSH38", + "input": { + "nodeId": "HkWOSWrB28", + "pinKey": "rkxwo0lWmm" + }, + "output": { + "nodeId": "BJluSWHrhU", + "pinKey": "__out__" + } + }, + { + "id": "ry6_BZrH3U", + "input": { + "nodeId": "HkzOS-BrhL", + "pinKey": "BJhHwoRb7" + }, + "output": { + "nodeId": "Hy4_HWHShU", + "pinKey": "__out__" + } + }, + { + "id": "rynuBbHHhU", + "input": { + "nodeId": "HkzOS-BrhL", + "pinKey": "rklUo8jA-Q" + }, + "output": { + "nodeId": "HkWOSWrB28", + "pinKey": "rJrPsAgWXm" + } + } + ], + "nodes": [ + { + "description": "An established internet connection", + "id": "B1OS-rS3I", + "label": "INET", + "position": { + "units": "slots", + "x": 3, + "y": 0 + }, + "type": "xod/patch-nodes/input-t1" + }, + { + "id": "B1XuB-SH3U", + "label": "RST", + "position": { + "units": "slots", + "x": 10, + "y": 1 + }, + "type": "xod/patch-nodes/to-bus" + }, + { + "boundLiterals": { + "__out__": "On Boot" + }, + "description": "Get the external IP.", + "id": "BJluSWHrhU", + "label": "INIT", + "position": { + "units": "slots", + "x": 8, + "y": 0 + }, + "type": "xod/patch-nodes/input-pulse" + }, + { + "boundLiterals": { + "S1bGvmAWQ": "'\"'" + }, + "id": "HJ8vMrS2L", + "position": { + "units": "slots", + "x": 3, + "y": 4 + }, + "type": "xod/stream/pass-until" + }, + { + "boundLiterals": { + "HkPwjCgZmX": "\"api.xod.io\"", + "SkWvi0lWQ7": "\"/httpbin/ip\"" + }, + "id": "HkWOSWrB28", + "position": { + "units": "slots", + "x": 3, + "y": 1 + }, + "type": "xod/net/http-get" + }, + { + "boundLiterals": { + "rkZ8oIj0-m": "\"origin\":\"\"" + }, + "id": "HkzOS-BrhL", + "position": { + "units": "slots", + "x": 3, + "y": 3 + }, + "type": "xod/stream/pass-from-sequence" + }, + { + "id": "Hy4_HWHShU", + "label": "RST", + "position": { + "units": "slots", + "x": 10, + "y": 2 + }, + "type": "xod/patch-nodes/from-bus" + }, + { + "description": "Pulses when the IP is received.", + "id": "S1HuBWBS2I", + "label": "DONE", + "position": { + "units": "slots", + "x": 5, + "y": 6 + }, + "type": "xod/patch-nodes/output-pulse" + }, + { + "description": "The external IP address.", + "id": "Syv_rWrSn8", + "label": "IP", + "position": { + "units": "slots", + "x": 2, + "y": 6 + }, + "type": "xod/patch-nodes/output-string" + }, + { + "boundLiterals": { + "HkAv2Av-X": "15" + }, + "id": "rJ8drZHr2I", + "position": { + "units": "slots", + "x": 2, + "y": 5 + }, + "type": "xod/stream/accumulate-string" + } + ] +} diff --git a/workspace/__lib__/xod-cloud/basics/now-iso/patch.xodp b/workspace/__lib__/xod-cloud/basics/now-iso/patch.xodp new file mode 100644 index 000000000..a7d19bc7a --- /dev/null +++ b/workspace/__lib__/xod-cloud/basics/now-iso/patch.xodp @@ -0,0 +1,260 @@ +{ + "description": "Gets a current datetime in ISO format from a XOD Cloud API.", + "links": [ + { + "id": "B121bBBnI", + "input": { + "nodeId": "S16AgrH3L", + "pinKey": "B1RU0OrDkb" + }, + "output": { + "nodeId": "rJYvfT4Hn8", + "pinKey": "__out__" + } + }, + { + "id": "H1wJbBHnU", + "input": { + "nodeId": "S16AgrH3L", + "pinKey": "Bkh8A_Sv1-" + }, + "output": { + "nodeId": "rJv7p4S2I", + "pinKey": "SkwBVl_bX" + } + }, + { + "id": "Hk2gvMp4rnL", + "input": { + "nodeId": "S1GvGTEBhI", + "pinKey": "B18iIoA-m" + }, + "output": { + "nodeId": "SyWDfaES2U", + "pinKey": "SkDiRgZQX" + } + }, + { + "id": "Hkk4wfpNH2U", + "input": { + "nodeId": "HJ_vfa4B38", + "pinKey": "__in__" + }, + "output": { + "nodeId": "rJlwfT4r2I", + "pinKey": "__out__" + } + }, + { + "id": "Hy04aVShU", + "input": { + "nodeId": "rJv7p4S2I", + "pinKey": "HJi_30PZX" + }, + "output": { + "nodeId": "S1GvGTEBhI", + "pinKey": "SkSGwoAZQ" + } + }, + { + "id": "S1-S6VB3L", + "input": { + "nodeId": "rJv7p4S2I", + "pinKey": "HyvKhAv-7" + }, + "output": { + "nodeId": "rJYvfT4Hn8", + "pinKey": "__out__" + } + }, + { + "id": "SJqxvzT4r2I", + "input": { + "nodeId": "SyWDfaES2U", + "pinKey": "Bk5vjCxW7Q" + }, + "output": { + "nodeId": "Sywf6EBhU", + "pinKey": "__out__" + } + }, + { + "id": "SJwZPM6Nrn8", + "input": { + "nodeId": "S1GvGTEBhI", + "pinKey": "BJhHwoRb7" + }, + "output": { + "nodeId": "rJYvfT4Hn8", + "pinKey": "__out__" + } + }, + { + "id": "SkTlvfpEB2U", + "input": { + "nodeId": "S1GvGTEBhI", + "pinKey": "rklUo8jA-Q" + }, + "output": { + "nodeId": "SyWDfaES2U", + "pinKey": "rJrPsAgWXm" + } + }, + { + "id": "r1hHpEr2U", + "input": { + "nodeId": "r1jBTESnU", + "pinKey": "__in__" + }, + "output": { + "nodeId": "rJv7p4S2I", + "pinKey": "S1s7pCDbQ" + } + }, + { + "id": "rJdLaVH3L", + "input": { + "nodeId": "rJv7p4S2I", + "pinKey": "r1NYhRDZ7" + }, + "output": { + "nodeId": "S1GvGTEBhI", + "pinKey": "SkYZwiRbm" + } + }, + { + "id": "rkjlDMp4HnL", + "input": { + "nodeId": "SyWDfaES2U", + "pinKey": "rkxwo0lWmm" + }, + "output": { + "nodeId": "rJlwfT4r2I", + "pinKey": "__out__" + } + }, + { + "id": "ryYybHB3I", + "input": { + "nodeId": "S1tePMT4SnL", + "pinKey": "__in__" + }, + "output": { + "nodeId": "S16AgrH3L", + "pinKey": "HkyxURuSPyW" + } + } + ], + "nodes": [ + { + "id": "HJ_vfa4B38", + "label": "RST", + "position": { + "units": "slots", + "x": 8, + "y": 0 + }, + "type": "xod/patch-nodes/to-bus" + }, + { + "id": "S16AgrH3L", + "position": { + "units": "slots", + "x": 2, + "y": 4 + }, + "type": "xod/core/flip-flop" + }, + { + "boundLiterals": { + "rkZ8oIj0-m": "\"iso\":\"\"" + }, + "id": "S1GvGTEBhI", + "position": { + "units": "slots", + "x": 1, + "y": 2 + }, + "type": "xod/stream/pass-from-sequence" + }, + { + "description": "Pulses when the datetime received.", + "id": "S1tePMT4SnL", + "label": "DONE", + "position": { + "units": "slots", + "x": 2, + "y": 5 + }, + "type": "xod/patch-nodes/output-pulse" + }, + { + "boundLiterals": { + "HkPwjCgZmX": "\"api.xod.io\"", + "SkWvi0lWQ7": "\"/httpbin/now\"" + }, + "id": "SyWDfaES2U", + "position": { + "units": "slots", + "x": 1, + "y": 0 + }, + "type": "xod/net/http-get" + }, + { + "description": "An established internet connection", + "id": "Sywf6EBhU", + "label": "INET", + "position": { + "units": "slots", + "x": 1, + "y": -1 + }, + "type": "xod/patch-nodes/input-t1" + }, + { + "description": "A current datettime in ISO format.", + "id": "r1jBTESnU", + "label": "ISO", + "position": { + "units": "slots", + "x": 0, + "y": 5 + }, + "type": "xod/patch-nodes/output-string" + }, + { + "id": "rJYvfT4Hn8", + "label": "RST", + "position": { + "units": "slots", + "x": 4, + "y": 1 + }, + "type": "xod/patch-nodes/from-bus" + }, + { + "description": "Request the current datettime.", + "id": "rJlwfT4r2I", + "label": "INIT", + "position": { + "units": "slots", + "x": 6, + "y": -1 + }, + "type": "xod/patch-nodes/input-pulse" + }, + { + "boundLiterals": { + "HkAv2Av-X": "24" + }, + "id": "rJv7p4S2I", + "position": { + "units": "slots", + "x": 0, + "y": 3 + }, + "type": "xod/stream/accumulate-string" + } + ] +} diff --git a/workspace/__lib__/xod-cloud/basics/now/patch.xodp b/workspace/__lib__/xod-cloud/basics/now/patch.xodp new file mode 100644 index 000000000..023a53c26 --- /dev/null +++ b/workspace/__lib__/xod-cloud/basics/now/patch.xodp @@ -0,0 +1,270 @@ +{ + "description": "Gets a current datetime from a XOD Cloud API.", + "links": [ + { + "id": "ByHqBqLnU", + "input": { + "nodeId": "H1m9BcL2L", + "pinKey": "B18iIoA-m" + }, + "output": { + "nodeId": "Sk-t4rqL3L", + "pinKey": "SkDiRgZQX" + } + }, + { + "id": "ByHtVHcU3I", + "input": { + "nodeId": "Sk-t4rqL3L", + "pinKey": "Bk5vjCxW7Q" + }, + "output": { + "nodeId": "r1lFErc828", + "pinKey": "__out__" + } + }, + { + "id": "H1flL5Un8", + "input": { + "nodeId": "ry31Lc83I", + "pinKey": "ryzE3DO83I" + }, + "output": { + "nodeId": "BJsCSqU2I", + "pinKey": "B1GszSOU38" + } + }, + { + "id": "Hk8tgey6L", + "input": { + "nodeId": "Sk0OelypI", + "pinKey": "__in__" + }, + "output": { + "nodeId": "BJsCSqU2I", + "pinKey": "BJTWS_Lh8" + } + }, + { + "id": "HkIqBcUh8", + "input": { + "nodeId": "H1m9BcL2L", + "pinKey": "rklUo8jA-Q" + }, + "output": { + "nodeId": "Sk-t4rqL3L", + "pinKey": "rJrPsAgWXm" + } + }, + { + "id": "S1ghI582U", + "input": { + "nodeId": "SkJnLc82I", + "pinKey": "__in__" + }, + "output": { + "nodeId": "HyF4Hq828", + "pinKey": "__out__" + } + }, + { + "id": "SJhRHc8hL", + "input": { + "nodeId": "BJsCSqU2I", + "pinKey": "ryNpbr_L3U" + }, + "output": { + "nodeId": "H1m9BcL2L", + "pinKey": "SkSGwoAZQ" + } + }, + { + "id": "SkbnI5I3L", + "input": { + "nodeId": "H1m9BcL2L", + "pinKey": "BJhHwoRb7" + }, + "output": { + "nodeId": "SkJnLc82I", + "pinKey": "__out__" + } + }, + { + "id": "Sy6Rr9Uh8", + "input": { + "nodeId": "BJsCSqU2I", + "pinKey": "H1faWHuInL" + }, + "output": { + "nodeId": "H1m9BcL2L", + "pinKey": "SkYZwiRbm" + } + }, + { + "id": "SyNFNHqInI", + "input": { + "nodeId": "Sk-t4rqL3L", + "pinKey": "rkxwo0lWmm" + }, + "output": { + "nodeId": "HyF4Hq828", + "pinKey": "__out__" + } + }, + { + "id": "r101U9L2L", + "input": { + "nodeId": "ry31Lc83I", + "pinKey": "HJbV2vdL3I" + }, + "output": { + "nodeId": "BJsCSqU2I", + "pinKey": "HJWjGBdIhL" + } + }, + { + "id": "rJkeL5LhI", + "input": { + "nodeId": "ry31Lc83I", + "pinKey": "HJg4hvuL3L" + }, + "output": { + "nodeId": "BJsCSqU2I", + "pinKey": "SkofSOLh8" + } + }, + { + "id": "rJmn8cIn8", + "input": { + "nodeId": "BJsCSqU2I", + "pinKey": "HympbBOLh8" + }, + "output": { + "nodeId": "SkJnLc82I", + "pinKey": "__out__" + } + }, + { + "id": "ry2eL5I28", + "input": { + "nodeId": "ryFe8qI3U", + "pinKey": "__in__" + }, + "output": { + "nodeId": "ry31Lc83I", + "pinKey": "rys3POU3L" + } + }, + { + "id": "ryxeI9U3L", + "input": { + "nodeId": "ry31Lc83I", + "pinKey": "HkNnPd8nI" + }, + "output": { + "nodeId": "BJsCSqU2I", + "pinKey": "ByeifH_82L" + } + } + ], + "nodes": [ + { + "id": "BJsCSqU2I", + "position": { + "units": "slots", + "x": 0, + "y": 3 + }, + "type": "xod/stream/parse-u32" + }, + { + "boundLiterals": { + "rkZ8oIj0-m": "\"\\n\\r\\n\"" + }, + "id": "H1m9BcL2L", + "position": { + "units": "slots", + "x": 0, + "y": 2 + }, + "type": "xod/stream/pass-from-sequence" + }, + { + "boundLiterals": { + "__out__": "On Boot" + }, + "description": "Request the current datettime.", + "id": "HyF4Hq828", + "label": "INIT", + "position": { + "units": "slots", + "x": 5, + "y": 0 + }, + "type": "xod/patch-nodes/input-pulse" + }, + { + "boundLiterals": { + "HkPwjCgZmX": "\"api.xod.io\"", + "SkWvi0lWQ7": "\"/httpbin/now/unix\"" + }, + "id": "Sk-t4rqL3L", + "position": { + "units": "slots", + "x": 0, + "y": 1 + }, + "type": "xod/net/http-get" + }, + { + "description": "Pulses when the datetime received.", + "id": "Sk0OelypI", + "label": "DONE", + "position": { + "units": "slots", + "x": 4, + "y": 5 + }, + "type": "xod/patch-nodes/output-pulse" + }, + { + "id": "SkJnLc82I", + "position": { + "units": "slots", + "x": 6, + "y": 1 + }, + "type": "xod/patch-nodes/jumper" + }, + { + "description": "An established internet connection", + "id": "r1lFErc828", + "label": "INET", + "position": { + "units": "slots", + "x": 0, + "y": 0 + }, + "type": "xod/patch-nodes/input-t1" + }, + { + "id": "ry31Lc83I", + "position": { + "units": "slots", + "x": 0, + "y": 4 + }, + "type": "xod/datetime/from-posix" + }, + { + "description": "A current datetime.", + "id": "ryFe8qI3U", + "position": { + "units": "slots", + "x": 0, + "y": 5 + }, + "type": "xod/datetime/output-datetime" + } + ] +} diff --git a/workspace/__lib__/xod-cloud/basics/project.xod b/workspace/__lib__/xod-cloud/basics/project.xod new file mode 100644 index 000000000..c29e54f24 --- /dev/null +++ b/workspace/__lib__/xod-cloud/basics/project.xod @@ -0,0 +1,9 @@ +{ + "authors": [ + "XOD" + ], + "description": "Nodes to get some basic data from the XOD Cloud API", + "license": "AGPL-3.0", + "name": "basics", + "version": "0.1.0" +} diff --git a/workspace/__lib__/xod-cloud/feeds/cloud-boolean-custom/patch.xodp b/workspace/__lib__/xod-cloud/feeds/cloud-boolean-custom/patch.xodp new file mode 100644 index 000000000..6c2bee1eb --- /dev/null +++ b/workspace/__lib__/xod-cloud/feeds/cloud-boolean-custom/patch.xodp @@ -0,0 +1,312 @@ +{ + "description": "Gets a boolean value from the feed.", + "links": [ + { + "id": "BJJSU7_aU", + "input": { + "nodeId": "BJFYBdJ68", + "pinKey": "HJi_30PZX" + }, + "output": { + "nodeId": "Hke97LX_6I", + "pinKey": "H1a4S7OaI" + } + }, + { + "id": "BkCVLmd6I", + "input": { + "nodeId": "BJFYBdJ68", + "pinKey": "r1NYhRDZ7" + }, + "output": { + "nodeId": "Hke97LX_6I", + "pinKey": "HJaUrmda8" + } + }, + { + "id": "BkQS87OTU", + "input": { + "nodeId": "BJFYBdJ68", + "pinKey": "HyvKhAv-7" + }, + "output": { + "nodeId": "B1z-efOk6L", + "pinKey": "__out__" + } + }, + { + "id": "H1aBIm_p8", + "input": { + "nodeId": "Hk7ZxGd1TU", + "pinKey": "__in__" + }, + "output": { + "nodeId": "SJq7IQda8", + "pinKey": "SJVql9lXr" + } + }, + { + "id": "H1oB87ua8", + "input": { + "nodeId": "SJq7IQda8", + "pinKey": "HkFFgqx7B" + }, + "output": { + "nodeId": "BJFYBdJ68", + "pinKey": "SkwBVl_bX" + } + }, + { + "id": "H1vEUmu6U", + "input": { + "nodeId": "Hke97LX_6I", + "pinKey": "SkLSXrXupL" + }, + "output": { + "nodeId": "Hkjbefdya8", + "pinKey": "__out__" + } + }, + { + "id": "HkAJLdkaU", + "input": { + "nodeId": "Hy6y8_k68", + "pinKey": "__in__" + }, + "output": { + "nodeId": "r1G18dypI", + "pinKey": "H1E8AuSPkZ" + } + }, + { + "id": "SJOJUuya8", + "input": { + "nodeId": "r1G18dypI", + "pinKey": "rJXICuSwyW" + }, + "output": { + "nodeId": "BJFYBdJ68", + "pinKey": "S1s7pCDbQ" + } + }, + { + "id": "Sk4V8mOp8", + "input": { + "nodeId": "Hke97LX_6I", + "pinKey": "H1DrmHXOTU" + }, + "output": { + "nodeId": "BJhZez_yTU", + "pinKey": "__out__" + } + }, + { + "id": "SkHHU7upI", + "input": { + "nodeId": "SJq7IQda8", + "pinKey": "HyDtx5xmS" + }, + "output": { + "nodeId": "B1z-efOk6L", + "pinKey": "__out__" + } + }, + { + "id": "SkIEU7upI", + "input": { + "nodeId": "Hke97LX_6I", + "pinKey": "r1OSXSXu68" + }, + "output": { + "nodeId": "SJTZxf_k6L", + "pinKey": "__out__" + } + }, + { + "id": "r1SE87u6I", + "input": { + "nodeId": "Hke97LX_6I", + "pinKey": "ry-r7rXO6I" + }, + "output": { + "nodeId": "SyVZxMOJp8", + "pinKey": "__out__" + } + }, + { + "id": "rk7EIXu68", + "input": { + "nodeId": "Hke97LX_6I", + "pinKey": "HkgHQrQdpL" + }, + "output": { + "nodeId": "B1z-efOk6L", + "pinKey": "__out__" + } + }, + { + "id": "rkZ5XLmOTI", + "input": { + "nodeId": "SJq7IQda8", + "pinKey": "ByFqg5eXr" + }, + "output": { + "nodeId": "Hke97LX_6I", + "pinKey": "HyorQBQ_6I" + } + }, + { + "id": "rkkEUQda8", + "input": { + "nodeId": "Hke97LX_6I", + "pinKey": "Sk0mrXuTL" + }, + "output": { + "nodeId": "SyRbeMuyTI", + "pinKey": "__out__" + } + } + ], + "nodes": [ + { + "boundLiterals": { + "__out__": "On Boot" + }, + "description": "Request the value from the cloud", + "id": "B1z-efOk6L", + "label": "DO", + "position": { + "units": "slots", + "x": 5, + "y": 0 + }, + "type": "xod/patch-nodes/input-pulse" + }, + { + "boundLiterals": { + "HkAv2Av-X": "4" + }, + "id": "BJFYBdJ68", + "position": { + "units": "slots", + "x": -1, + "y": 2 + }, + "type": "xod/stream/accumulate-string" + }, + { + "description": "Feed path starting from the project name. The full feed path will be `//`.", + "id": "BJhZez_yTU", + "label": "FEED", + "position": { + "units": "slots", + "x": 4, + "y": 0 + }, + "type": "xod/patch-nodes/input-string" + }, + { + "description": "Pulses when the value is successfully stored", + "id": "Hk7ZxGd1TU", + "label": "DONE", + "position": { + "units": "slots", + "x": 1, + "y": 4 + }, + "type": "xod/patch-nodes/output-pulse" + }, + { + "id": "Hke97LX_6I", + "position": { + "units": "slots", + "x": 0, + "y": 1 + }, + "type": "@/feeds-request" + }, + { + "boundLiterals": { + "__out__": "=XOD_TOKEN" + }, + "description": "XOD Cloud API Token", + "id": "Hkjbefdya8", + "label": "TOK", + "position": { + "units": "slots", + "x": 1, + "y": 0 + }, + "type": "xod/patch-nodes/input-string" + }, + { + "id": "Hy6y8_k68", + "position": { + "units": "slots", + "x": -1, + "y": 4 + }, + "type": "xod/patch-nodes/output-boolean" + }, + { + "boundLiterals": { + "__out__": "=XOD_USERNAME" + }, + "description": "XOD Cloud username. Used for the full feed path construction", + "id": "SJTZxf_k6L", + "label": "USER", + "position": { + "units": "slots", + "x": 2, + "y": 0 + }, + "type": "xod/patch-nodes/input-string" + }, + { + "id": "SJq7IQda8", + "position": { + "units": "slots", + "x": 1, + "y": 3 + }, + "type": "xod/core/wait-all" + }, + { + "description": "An established internet connection", + "id": "SyRbeMuyTI", + "label": "INET", + "position": { + "units": "slots", + "x": 0, + "y": 0 + }, + "type": "xod/patch-nodes/input-t1" + }, + { + "boundLiterals": { + "__out__": "=XOD_PROJECT" + }, + "description": "XOD Cloud project name. Used for the full feed path construction", + "id": "SyVZxMOJp8", + "label": "PROJ", + "position": { + "units": "slots", + "x": 3, + "y": 0 + }, + "type": "xod/patch-nodes/input-string" + }, + { + "boundLiterals": { + "HJG8C_SPkb": "\"true\"" + }, + "id": "r1G18dypI", + "position": { + "units": "slots", + "x": -1, + "y": 3 + }, + "type": "xod/core/equal" + } + ] +} diff --git a/workspace/__lib__/xod-cloud/feeds/cloud-number-custom/patch.xodp b/workspace/__lib__/xod-cloud/feeds/cloud-number-custom/patch.xodp new file mode 100644 index 000000000..3abe9c0c5 --- /dev/null +++ b/workspace/__lib__/xod-cloud/feeds/cloud-number-custom/patch.xodp @@ -0,0 +1,286 @@ +{ + "description": "Gets a number value from the feed.", + "links": [ + { + "id": "BJpcS7dTI", + "input": { + "nodeId": "BJ4KB7Op8", + "pinKey": "r1OSXSXu68" + }, + "output": { + "nodeId": "rkDW1ZECnI", + "pinKey": "__out__" + } + }, + { + "id": "ByE3HX_6L", + "input": { + "nodeId": "S1XkUK0hU", + "pinKey": "Bymaw7FAhL" + }, + "output": { + "nodeId": "H1byZERnU", + "pinKey": "__out__" + } + }, + { + "id": "H1kiBmOaU", + "input": { + "nodeId": "BJ4KB7Op8", + "pinKey": "H1DrmHXOTU" + }, + "output": { + "nodeId": "r1Z-y-4CnU", + "pinKey": "__out__" + } + }, + { + "id": "HJ9y8F0h8", + "input": { + "nodeId": "SJ2G4N0hU", + "pinKey": "__in__" + }, + "output": { + "nodeId": "S1XkUK0hU", + "pinKey": "Sk-6vQKRnL" + } + }, + { + "id": "HyPgUm_pI", + "input": { + "nodeId": "ryblUQd6L", + "pinKey": "ByFqg5eXr" + }, + "output": { + "nodeId": "BJ4KB7Op8", + "pinKey": "HyorQBQ_6I" + } + }, + { + "id": "Hyscrm_6U", + "input": { + "nodeId": "BJ4KB7Op8", + "pinKey": "SkLSXrXupL" + }, + "output": { + "nodeId": "r1L-1bEC3L", + "pinKey": "__out__" + } + }, + { + "id": "S18lLm_pI", + "input": { + "nodeId": "ryblUQd6L", + "pinKey": "HkFFgqx7B" + }, + "output": { + "nodeId": "S1XkUK0hU", + "pinKey": "rkawmFR3I" + } + }, + { + "id": "S1XiHXda8", + "input": { + "nodeId": "BJ4KB7Op8", + "pinKey": "HkgHQrQdpL" + }, + "output": { + "nodeId": "H1byZERnU", + "pinKey": "__out__" + } + }, + { + "id": "S1cjHQuTI", + "input": { + "nodeId": "S1XkUK0hU", + "pinKey": "ByEaDQKC3I" + }, + "output": { + "nodeId": "BJ4KB7Op8", + "pinKey": "H1a4S7OaI" + } + }, + { + "id": "SJ5crm_TL", + "input": { + "nodeId": "BJ4KB7Op8", + "pinKey": "Sk0mrXuTL" + }, + "output": { + "nodeId": "rkuZJ-NA3U", + "pinKey": "__out__" + } + }, + { + "id": "SJjx8QOTI", + "input": { + "nodeId": "ryblUQd6L", + "pinKey": "HyDtx5xmS" + }, + "output": { + "nodeId": "H1byZERnU", + "pinKey": "__out__" + } + }, + { + "id": "SyCqSQO6L", + "input": { + "nodeId": "BJ4KB7Op8", + "pinKey": "ry-r7rXO6I" + }, + "output": { + "nodeId": "Hk9b1b4Rh8", + "pinKey": "__out__" + } + }, + { + "id": "rkojH7daL", + "input": { + "nodeId": "S1XkUK0hU", + "pinKey": "Byfpw7FCnU" + }, + "output": { + "nodeId": "BJ4KB7Op8", + "pinKey": "HJaUrmda8" + } + }, + { + "id": "ryFl8XO6L", + "input": { + "nodeId": "HJrWyb40nL", + "pinKey": "__in__" + }, + "output": { + "nodeId": "ryblUQd6L", + "pinKey": "SJVql9lXr" + } + } + ], + "nodes": [ + { + "id": "BJ4KB7Op8", + "position": { + "units": "slots", + "x": 0, + "y": 1 + }, + "type": "@/feeds-request" + }, + { + "boundLiterals": { + "__out__": "On Boot" + }, + "description": "Request the value from the cloud", + "id": "H1byZERnU", + "label": "DO", + "position": { + "units": "slots", + "x": 5, + "y": 0 + }, + "type": "xod/patch-nodes/input-pulse" + }, + { + "description": "Pulses when the value is successfully received", + "id": "HJrWyb40nL", + "label": "DONE", + "position": { + "units": "slots", + "x": 1, + "y": 4 + }, + "type": "xod/patch-nodes/output-pulse" + }, + { + "boundLiterals": { + "__out__": "=XOD_PROJECT" + }, + "description": "XOD Cloud project name. Used for the full feed path construction", + "id": "Hk9b1b4Rh8", + "label": "PROJ", + "position": { + "units": "slots", + "x": 3, + "y": 0 + }, + "type": "xod/patch-nodes/input-string" + }, + { + "id": "S1XkUK0hU", + "position": { + "units": "slots", + "x": 0, + "y": 2 + }, + "type": "xod/stream/parse-number" + }, + { + "id": "SJ2G4N0hU", + "position": { + "units": "slots", + "x": 0, + "y": 4 + }, + "type": "xod/patch-nodes/output-number" + }, + { + "boundLiterals": { + "__out__": "=XOD_TOKEN" + }, + "description": "XOD Cloud API Token", + "id": "r1L-1bEC3L", + "label": "TOK", + "position": { + "units": "slots", + "x": 1, + "y": 0 + }, + "type": "xod/patch-nodes/input-string" + }, + { + "description": "Feed path starting from the project name. The full feed path will be `//`.", + "id": "r1Z-y-4CnU", + "label": "FEED", + "position": { + "units": "slots", + "x": 4, + "y": 0 + }, + "type": "xod/patch-nodes/input-string" + }, + { + "boundLiterals": { + "__out__": "=XOD_USERNAME" + }, + "description": "XOD Cloud username. Used for the full feed path construction", + "id": "rkDW1ZECnI", + "label": "USER", + "position": { + "units": "slots", + "x": 2, + "y": 0 + }, + "type": "xod/patch-nodes/input-string" + }, + { + "description": "An established internet connection", + "id": "rkuZJ-NA3U", + "label": "INET", + "position": { + "units": "slots", + "x": 0, + "y": 0 + }, + "type": "xod/patch-nodes/input-t1" + }, + { + "id": "ryblUQd6L", + "position": { + "units": "slots", + "x": 1, + "y": 3 + }, + "type": "xod/core/wait-all" + } + ] +} diff --git a/workspace/__lib__/xod-cloud/feeds/cloud-store-custom/patch.xodp b/workspace/__lib__/xod-cloud/feeds/cloud-store-custom/patch.xodp index 1aca2867c..0306911fd 100644 --- a/workspace/__lib__/xod-cloud/feeds/cloud-store-custom/patch.xodp +++ b/workspace/__lib__/xod-cloud/feeds/cloud-store-custom/patch.xodp @@ -23,6 +23,17 @@ "pinKey": "H1JuNDn9E" } }, + { + "id": "BkpnSU5pU", + "input": { + "nodeId": "Hkpi3_ucH", + "pinKey": "B1V0v3O_9S" + }, + "output": { + "nodeId": "HJanK-0tS", + "pinKey": "SJGl9r9l-m7" + } + }, { "id": "Byhp2dOcH", "input": { @@ -100,17 +111,6 @@ "pinKey": "__out__" } }, - { - "id": "SyW22dO9B", - "input": { - "nodeId": "Hkpi3_ucH", - "pinKey": "B1V0v3O_9S" - }, - "output": { - "nodeId": "B1FXSb0YB", - "pinKey": "__out__" - } - }, { "id": "SyocHbAFr", "input": { diff --git a/workspace/__lib__/xod-cloud/feeds/cloud-string-custom/patch.xodp b/workspace/__lib__/xod-cloud/feeds/cloud-string-custom/patch.xodp new file mode 100644 index 000000000..3a95a8a33 --- /dev/null +++ b/workspace/__lib__/xod-cloud/feeds/cloud-string-custom/patch.xodp @@ -0,0 +1,291 @@ +{ + "description": "Gets a string value from the feed.", + "links": [ + { + "id": "B1Vd87uaU", + "input": { + "nodeId": "ByldwLm_pU", + "pinKey": "ry-r7rXO6I" + }, + "output": { + "nodeId": "H14nEW_JaU", + "pinKey": "__out__" + } + }, + { + "id": "BJ7OLmO6I", + "input": { + "nodeId": "ByldwLm_pU", + "pinKey": "H1DrmHXOTU" + }, + "output": { + "nodeId": "ryh34Z_1aU", + "pinKey": "__out__" + } + }, + { + "id": "BJL5L7d6L", + "input": { + "nodeId": "S1prWOk68", + "pinKey": "HyvKhAv-7" + }, + "output": { + "nodeId": "Syz3EWOkp8", + "pinKey": "__out__" + } + }, + { + "id": "ByUOImO68", + "input": { + "nodeId": "ByldwLm_pU", + "pinKey": "SkLSXrXupL" + }, + "output": { + "nodeId": "ByjnNWuypU", + "pinKey": "__out__" + } + }, + { + "id": "ByiPL7OpU", + "input": { + "nodeId": "ByldwLm_pU", + "pinKey": "Sk0mrXuTL" + }, + "output": { + "nodeId": "ByCnVZu1aL", + "pinKey": "__out__" + } + }, + { + "id": "ByvKLX_pU", + "input": { + "nodeId": "SkQn4Z_J6U", + "pinKey": "__in__" + }, + "output": { + "nodeId": "ByldwLm_pU", + "pinKey": "HyorQBQ_6I" + } + }, + { + "id": "H1sOUX_a8", + "input": { + "nodeId": "S1prWOk68", + "pinKey": "r1NYhRDZ7" + }, + "output": { + "nodeId": "ByldwLm_pU", + "pinKey": "HJaUrmda8" + } + }, + { + "id": "Skn_U7OaL", + "input": { + "nodeId": "S1prWOk68", + "pinKey": "HJi_30PZX" + }, + "output": { + "nodeId": "ByldwLm_pU", + "pinKey": "H1a4S7OaI" + } + }, + { + "id": "r1BdImu6I", + "input": { + "nodeId": "ByldwLm_pU", + "pinKey": "r1OSXSXu68" + }, + "output": { + "nodeId": "Bkah4W_ka8", + "pinKey": "__out__" + } + }, + { + "id": "r1PqWuyTI", + "input": { + "nodeId": "ByIcWO1TU", + "pinKey": "__in__" + }, + "output": { + "nodeId": "S1prWOk68", + "pinKey": "S1s7pCDbQ" + } + }, + { + "id": "rJg9ZOk6U", + "input": { + "nodeId": "rJKwbd16L", + "pinKey": "__in__" + }, + "output": { + "nodeId": "S1prWOk68", + "pinKey": "SkwBVl_bX" + } + }, + { + "id": "rJz_IQ_T8", + "input": { + "nodeId": "ByldwLm_pU", + "pinKey": "HkgHQrQdpL" + }, + "output": { + "nodeId": "Syz3EWOkp8", + "pinKey": "__out__" + } + }, + { + "id": "rk3cPdkpU", + "input": { + "nodeId": "S1prWOk68", + "pinKey": "HkAv2Av-X" + }, + "output": { + "nodeId": "HJSqD_yp8", + "pinKey": "__out__" + } + } + ], + "nodes": [ + { + "boundLiterals": { + "__out__": "=XOD_USERNAME" + }, + "description": "XOD Cloud username. Used for the full feed path construction", + "id": "Bkah4W_ka8", + "label": "USER", + "position": { + "units": "slots", + "x": 2, + "y": 0 + }, + "type": "xod/patch-nodes/input-string" + }, + { + "description": "An established internet connection", + "id": "ByCnVZu1aL", + "label": "INET", + "position": { + "units": "slots", + "x": -3, + "y": 0 + }, + "type": "xod/patch-nodes/input-t1" + }, + { + "id": "ByIcWO1TU", + "position": { + "units": "slots", + "x": -2, + "y": 4 + }, + "type": "xod/patch-nodes/output-string" + }, + { + "boundLiterals": { + "__out__": "=XOD_TOKEN" + }, + "description": "XOD Cloud API Token", + "id": "ByjnNWuypU", + "label": "TOK", + "position": { + "units": "slots", + "x": 1, + "y": 0 + }, + "type": "xod/patch-nodes/input-string" + }, + { + "id": "ByldwLm_pU", + "position": { + "units": "slots", + "x": 0, + "y": 1 + }, + "type": "@/feeds-request" + }, + { + "boundLiterals": { + "__out__": "=XOD_PROJECT" + }, + "description": "XOD Cloud project name. Used for the full feed path construction", + "id": "H14nEW_JaU", + "label": "PROJ", + "position": { + "units": "slots", + "x": 3, + "y": 0 + }, + "type": "xod/patch-nodes/input-string" + }, + { + "boundLiterals": { + "__out__": "16" + }, + "description": "The capacity of the string buffer. Defines the maximum length. Must be a constant value. Any changes during program execution will be ignored.", + "id": "HJSqD_yp8", + "label": "CAP", + "position": { + "units": "slots", + "x": -2, + "y": 0 + }, + "type": "xod/patch-nodes/input-number" + }, + { + "id": "S1prWOk68", + "position": { + "units": "slots", + "x": -2, + "y": 2 + }, + "type": "xod/stream/accumulate-string" + }, + { + "description": "Pulses when the value is successfully stored", + "id": "SkQn4Z_J6U", + "label": "DONE", + "position": { + "units": "slots", + "x": 2, + "y": 4 + }, + "type": "xod/patch-nodes/output-pulse" + }, + { + "boundLiterals": { + "__out__": "On Boot" + }, + "description": "Request the value from the cloud", + "id": "Syz3EWOkp8", + "label": "DO", + "position": { + "units": "slots", + "x": 5, + "y": 0 + }, + "type": "xod/patch-nodes/input-pulse" + }, + { + "description": "Pulses when string reached maximum length and pushed character was ignored", + "id": "rJKwbd16L", + "label": "FULL", + "position": { + "units": "slots", + "x": 0, + "y": 4 + }, + "type": "xod/patch-nodes/output-pulse" + }, + { + "description": "Feed path starting from the project name. The full feed path will be `//`.", + "id": "ryh34Z_1aU", + "label": "FEED", + "position": { + "units": "slots", + "x": 4, + "y": 0 + }, + "type": "xod/patch-nodes/input-string" + } + ] +} diff --git a/workspace/__lib__/xod-cloud/feeds/feeds-request/patch.xodp b/workspace/__lib__/xod-cloud/feeds/feeds-request/patch.xodp new file mode 100644 index 000000000..193453807 --- /dev/null +++ b/workspace/__lib__/xod-cloud/feeds/feeds-request/patch.xodp @@ -0,0 +1,427 @@ +{ + "links": [ + { + "id": "B1ixrXHmd6I", + "input": { + "nodeId": "HyorQBQ_6I", + "pinKey": "__in__" + }, + "output": { + "nodeId": "H1trQrXOa8", + "pinKey": "H1JuNDn9E" + } + }, + { + "id": "BJ5vBX_TL", + "input": { + "nodeId": "HJaUrmda8", + "pinKey": "__in__" + }, + "output": { + "nodeId": "rJ5H7rQ_TI", + "pinKey": "SkYZwiRbm" + } + }, + { + "id": "BJaSQH7u6L", + "input": { + "nodeId": "SJSSXBm_pI", + "pinKey": "rJJHNrVuM-$2" + }, + "output": { + "nodeId": "H1DrmHXOTU", + "pinKey": "__out__" + } + }, + { + "id": "BkNgSmB7OpI", + "input": { + "nodeId": "SJSSXBm_pI", + "pinKey": "rJJHNrVuM" + }, + "output": { + "nodeId": "r1OSXSXu68", + "pinKey": "__out__" + } + }, + { + "id": "ByZlSmS7OTU", + "input": { + "nodeId": "H1trQrXOa8", + "pinKey": "r13uED2cN" + }, + "output": { + "nodeId": "HyGrmBm_pU", + "pinKey": "SJ1onOOcB" + } + }, + { + "id": "HJoY27qaI", + "input": { + "nodeId": "HyGrmBm_pU", + "pinKey": "B1V0v3O_9S" + }, + "output": { + "nodeId": "ryHQSX_aL", + "pinKey": "SJGl9r9l-m7" + } + }, + { + "id": "HktgBQSX_pU", + "input": { + "nodeId": "HyQrQrm_aU", + "pinKey": "Hkqu9oaWb" + }, + "output": { + "nodeId": "SJSSXBm_pI", + "pinKey": "HJrBNr4dG" + } + }, + { + "id": "HyABmSmd6I", + "input": { + "nodeId": "S1EHmSmOa8", + "pinKey": "BkeKcj6ZZ" + }, + "output": { + "nodeId": "SkLSXrXupL", + "pinKey": "__out__" + } + }, + { + "id": "S1CNrQupU", + "input": { + "nodeId": "H1a4S7OaI", + "pinKey": "__in__" + }, + "output": { + "nodeId": "rJ5H7rQ_TI", + "pinKey": "SkSGwoAZQ" + } + }, + { + "id": "S1glHQH7d6I", + "input": { + "nodeId": "ryHQSX_aL", + "pinKey": "H1e9S9e-mQ" + }, + "output": { + "nodeId": "HkgHQrQdpL", + "pinKey": "__out__" + } + }, + { + "id": "S1reBmSXuaL", + "input": { + "nodeId": "ryHQSX_aL", + "pinKey": "HJzqrceZQm" + }, + "output": { + "nodeId": "HyQrQrm_aU", + "pinKey": "rksccsp-W" + } + }, + { + "id": "Sk5lHQBm_6L", + "input": { + "nodeId": "rJ5H7rQ_TI", + "pinKey": "B18iIoA-m" + }, + "output": { + "nodeId": "ryHQSX_aL", + "pinKey": "H15S9xWQX" + } + }, + { + "id": "SkvgS7SQu6L", + "input": { + "nodeId": "HyGrmBm_pU", + "pinKey": "SJICP3ducr" + }, + "output": { + "nodeId": "ryHQSX_aL", + "pinKey": "S1sqHqebm7" + } + }, + { + "id": "Sy1eHQSmdaI", + "input": { + "nodeId": "SJSSXBm_pI", + "pinKey": "rJJHNrVuM-$1" + }, + "output": { + "nodeId": "ry-r7rXO6I", + "pinKey": "__out__" + } + }, + { + "id": "SyOlBQrm_pL", + "input": { + "nodeId": "rJ5H7rQ_TI", + "pinKey": "rklUo8jA-Q" + }, + "output": { + "nodeId": "ryHQSX_aL", + "pinKey": "S1sqHqebm7" + } + }, + { + "id": "r12SQSQ_a8", + "input": { + "nodeId": "HyGrmBm_pU", + "pinKey": "SyPADnu_cr" + }, + "output": { + "nodeId": "ryHQSX_aL", + "pinKey": "H15S9xWQX" + } + }, + { + "id": "rJ7lBQBXuTU", + "input": { + "nodeId": "rJ5H7rQ_TI", + "pinKey": "BJhHwoRb7" + }, + "output": { + "nodeId": "HkgHQrQdpL", + "pinKey": "__out__" + } + }, + { + "id": "rJjLS7OpU", + "input": { + "nodeId": "H1trQrXOa8", + "pinKey": "rkdPED3cE" + }, + "output": { + "nodeId": "ryHQSX_aL", + "pinKey": "SJGl9r9l-m7" + } + }, + { + "id": "rkIlBXSQ_p8", + "input": { + "nodeId": "ryHQSX_aL", + "pinKey": "BJbecH5x-Xm" + }, + "output": { + "nodeId": "S1EHmSmOa8", + "pinKey": "rksccsp-W" + } + }, + { + "id": "ryl4HQdTU", + "input": { + "nodeId": "ryHQSX_aL", + "pinKey": "S1SP9lW7X" + }, + "output": { + "nodeId": "Sk0mrXuTL", + "pinKey": "__out__" + } + } + ], + "nodes": [ + { + "id": "BykYH7_aU", + "position": { + "units": "slots", + "x": 10, + "y": 0 + }, + "type": "xod/patch-nodes/utility" + }, + { + "description": "Feed path starting from the project name. The full feed path will be `//`.", + "id": "H1DrmHXOTU", + "label": "FEED", + "position": { + "units": "slots", + "x": 5, + "y": 0 + }, + "type": "xod/patch-nodes/input-string" + }, + { + "description": "Byte of the response data", + "id": "H1a4S7OaI", + "position": { + "units": "slots", + "x": 0, + "y": 7 + }, + "type": "xod/patch-nodes/output-byte" + }, + { + "id": "H1trQrXOa8", + "position": { + "units": "slots", + "x": 2, + "y": 6 + }, + "type": "xod/core/error" + }, + { + "description": "Pulses when the byte is received", + "id": "HJaUrmda8", + "label": "RCV", + "position": { + "units": "slots", + "x": 1, + "y": 7 + }, + "type": "xod/patch-nodes/output-pulse" + }, + { + "boundLiterals": { + "__out__": "On Boot" + }, + "description": "Request the value from the cloud", + "id": "HkgHQrQdpL", + "label": "DO", + "position": { + "units": "slots", + "x": 7, + "y": 0 + }, + "type": "xod/patch-nodes/input-pulse" + }, + { + "id": "HyGrmBm_pU", + "position": { + "units": "slots", + "x": 5, + "y": 5 + }, + "type": "@/is-non-200-response" + }, + { + "boundLiterals": { + "BkeKcj6ZZ": "\"?format=text\"", + "Hkqu9oaWb": "\"Authorization: Bearer \"" + }, + "id": "HyQrQrm_aU", + "position": { + "units": "slots", + "x": 1, + "y": 3 + }, + "type": "xod/core/concat" + }, + { + "description": "Pulses when the value is successfully stored", + "id": "HyorQBQ_6I", + "label": "DONE", + "position": { + "units": "slots", + "x": 2, + "y": 7 + }, + "type": "xod/patch-nodes/output-pulse" + }, + { + "boundLiterals": { + "Hkqu9oaWb": "\"Authorization: Bearer \"" + }, + "id": "S1EHmSmOa8", + "position": { + "units": "slots", + "x": 4, + "y": 3 + }, + "type": "xod/core/concat" + }, + { + "arityLevel": 3, + "boundLiterals": { + "HynENHNOz": "\"/iot/value\"", + "rJGQNB4df": "\"/\"" + }, + "id": "SJSSXBm_pI", + "position": { + "units": "slots", + "x": 1, + "y": 2 + }, + "type": "xod/core/join" + }, + { + "description": "An established internet connection", + "id": "Sk0mrXuTL", + "label": "INET", + "position": { + "units": "slots", + "x": 0, + "y": 0 + }, + "type": "xod/patch-nodes/input-t1" + }, + { + "boundLiterals": { + "__out__": "=XOD_TOKEN" + }, + "description": "XOD Cloud API Token", + "id": "SkLSXrXupL", + "label": "TOK", + "position": { + "units": "slots", + "x": 2, + "y": 0 + }, + "type": "xod/patch-nodes/input-string" + }, + { + "boundLiterals": { + "__out__": "=XOD_USERNAME" + }, + "description": "XOD Cloud username. Used for the full feed path construction", + "id": "r1OSXSXu68", + "label": "USER", + "position": { + "units": "slots", + "x": 3, + "y": 0 + }, + "type": "xod/patch-nodes/input-string" + }, + { + "boundLiterals": { + "rkZ8oIj0-m": "\"\\r\\n\\r\\n\"" + }, + "id": "rJ5H7rQ_TI", + "position": { + "units": "slots", + "x": 0, + "y": 5 + }, + "type": "xod/stream/pass-from-sequence" + }, + { + "boundLiterals": { + "__out__": "=XOD_PROJECT" + }, + "description": "XOD Cloud project name. Used for the full feed path construction", + "id": "ry-r7rXO6I", + "label": "PROJ", + "position": { + "units": "slots", + "x": 4, + "y": 0 + }, + "type": "xod/patch-nodes/input-string" + }, + { + "boundLiterals": { + "S1c9Hcl-7m": "\"GET\"", + "S1geqrqgWmX": "\"api.xod.io\"" + }, + "id": "ryHQSX_aL", + "position": { + "units": "slots", + "x": 0, + "y": 4 + }, + "type": "xod/net/http-request" + } + ] +} From b28c39d2cbe40bb6c42dd47e1a19893030383fb8 Mon Sep 17 00:00:00 2001 From: Kirill Shumilov Date: Thu, 11 Jun 2020 11:50:37 +0300 Subject: [PATCH 06/10] feat(stdlib): add a getter node `xod-cloud/feeds/cloud-number` for numeric values from feeds --- .../xod-cloud/feeds/cloud-number/patch.xodp | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 workspace/__lib__/xod-cloud/feeds/cloud-number/patch.xodp diff --git a/workspace/__lib__/xod-cloud/feeds/cloud-number/patch.xodp b/workspace/__lib__/xod-cloud/feeds/cloud-number/patch.xodp new file mode 100644 index 000000000..3af59b612 --- /dev/null +++ b/workspace/__lib__/xod-cloud/feeds/cloud-number/patch.xodp @@ -0,0 +1,130 @@ +{ + "description": "Gets a number value from the feed.", + "links": [ + { + "id": "BkoC4ECh8", + "input": { + "nodeId": "SyWRVVA3I", + "pinKey": "r1Z-y-4CnU" + }, + "output": { + "nodeId": "H1GSAN40nI", + "pinKey": "__out__" + } + }, + { + "id": "HylJBV0hL", + "input": { + "nodeId": "SyWRVVA3I", + "pinKey": "rkuZJ-NA3U" + }, + "output": { + "nodeId": "r1bBAVNAh8", + "pinKey": "__out__" + } + }, + { + "id": "S1kkrNR2L", + "input": { + "nodeId": "HkmBC4V0nU", + "pinKey": "__in__" + }, + "output": { + "nodeId": "SyWRVVA3I", + "pinKey": "HJrWyb40nL" + } + }, + { + "id": "SkL1HNR2U", + "input": { + "nodeId": "BJHJB4R2U", + "pinKey": "__in__" + }, + "output": { + "nodeId": "SyWRVVA3I", + "pinKey": "SJ2G4N0hU" + } + }, + { + "id": "r1ARNNR2I", + "input": { + "nodeId": "SyWRVVA3I", + "pinKey": "H1byZERnU" + }, + "output": { + "nodeId": "S1rCENRnL", + "pinKey": "__out__" + } + } + ], + "nodes": [ + { + "id": "BJHJB4R2U", + "position": { + "units": "slots", + "x": 0, + "y": 2 + }, + "type": "xod/patch-nodes/output-number" + }, + { + "boundLiterals": { + "__out__": "\"my-value\"" + }, + "description": "Feed path starting from the project name. The full feed path will be `//`", + "id": "H1GSAN40nI", + "label": "FEED", + "position": { + "units": "slots", + "x": 4, + "y": 0 + }, + "type": "xod/patch-nodes/input-string" + }, + { + "description": "Pulses when the value is successfully stored", + "id": "HkmBC4V0nU", + "label": "DONE", + "position": { + "units": "slots", + "x": 1, + "y": 2 + }, + "type": "xod/patch-nodes/output-pulse" + }, + { + "boundLiterals": { + "__out__": "On Boot" + }, + "description": "Request the value from the cloud", + "id": "S1rCENRnL", + "label": "DO", + "position": { + "units": "slots", + "x": 5, + "y": 0 + }, + "type": "xod/patch-nodes/input-pulse" + }, + { + "id": "SyWRVVA3I", + "position": { + "units": "slots", + "x": 0, + "y": 1 + }, + "type": "@/cloud-number-custom" + }, + { + "description": "An established internet connection", + "id": "r1bBAVNAh8", + "label": "INET", + "position": { + "units": "slots", + "x": 0, + "y": 0 + }, + "type": "xod/patch-nodes/input-t1" + } + ] +} From 8de5e287e9fdb75eaf4d92cd030f375e8ec47331 Mon Sep 17 00:00:00 2001 From: Kirill Shumilov Date: Thu, 11 Jun 2020 11:51:28 +0300 Subject: [PATCH 07/10] feat(tutorial): add five new chapters in the tutorial: custom types & internet --- .../013-custom-types/patch.xodp | 176 +++++++++++++ .../014-internet-tethering/patch.xodp | 148 +++++++++++ .../015-xod-cloud-feeds/patch.xodp | 127 ++++++++++ .../111-feed-messaging/patch.xodp | 239 ++++++++++++++++++ .../112-standalone-internet/patch.xodp | 114 +++++++++ 5 files changed, 804 insertions(+) create mode 100644 workspace/welcome-to-xod/013-custom-types/patch.xodp create mode 100644 workspace/welcome-to-xod/014-internet-tethering/patch.xodp create mode 100644 workspace/welcome-to-xod/015-xod-cloud-feeds/patch.xodp create mode 100644 workspace/welcome-to-xod/111-feed-messaging/patch.xodp create mode 100644 workspace/welcome-to-xod/112-standalone-internet/patch.xodp diff --git a/workspace/welcome-to-xod/013-custom-types/patch.xodp b/workspace/welcome-to-xod/013-custom-types/patch.xodp new file mode 100644 index 000000000..d55760f50 --- /dev/null +++ b/workspace/welcome-to-xod/013-custom-types/patch.xodp @@ -0,0 +1,176 @@ +{ + "comments": [ + { + "content": "# Custom Types\n\nIn addition to the primitive data types, XOD has more complicated _custom_ types. Custom types can consist of other types or wrap C++ classes.\n\nConsider custom type values like black boxes that can't do anything on their own. An author of the custom type always puts some nodes which operate on such custom type values. Use these to perform actions on custom type value, query the custom type data, or create and update the custom type values.\n\n## Datetime\n\nOn this patch, you see the `datetime` node, which takes few numbers and outputs a value of a custom type `xod/datetime/datetime`.\n\nThis type contains a so-called POSIX timestamp inside. The `xod/datetime` library provides nodes to manipulate the `datetime` and format it to in arbitrary way.\n\n- The `datetime` node is one of the *type constructors*. Note that the minimum value is 1st January of the 1970 year. It's a starting point of the Unix epoch.\n- The `add-seconds` node shifts the date by adding some number of seconds.\n- The `format-timestamp` node outputs the datetime in the default format.\n\nBind the current time and start the simulation.", + "id": "B1DHY9UnL", + "position": { + "units": "slots", + "x": 0, + "y": 0 + }, + "size": { + "height": 8, + "units": "slots", + "width": 7 + } + }, + { + "content": "## Excercise\n\nFormat the same datetime as \"24.03.2019 9:47 am\".\n\n1. Replace `format-timestamp` with the `unpack-datetime` node.\n2. Place an `am-pm` node and link it with the `HOUR` output.\n3. Place `if-else` node, link it with `AM` output and bind strings: \"am\" for `T` and \"pm\" for `F`.\n4. Construct a new datetime format using `concat` nodes as it is inside the `format-timestamp` node, including the \"am\"/\"pm\" suffix feature. \n\nRun the simulation and check it out.\n\nAdd or subtract some hours using the `tweak-number` node that is already on the patch, to ensure that \"am\" and \"pm\" suffix works.\n\n---\n\nYou'll discover that XOD uses custom types extensivelly. They encapsulate different hardware devices, interfaces, protocols, and so on.\n\nIf you want to learn how to implement your custom type, read the guide: \"[Defining Custom Types](https://xod.io/docs/guide/custom-types/)\".", + "id": "H1_-AcInI", + "position": { + "units": "slots", + "x": 17, + "y": 0 + }, + "size": { + "height": 6, + "units": "slots", + "width": 7 + } + }, + { + "content": "^\nAdd/Subtract hours", + "id": "S1rbyi8h8", + "position": { + "units": "slots", + "x": 12, + "y": 2 + }, + "size": { + "height": 1, + "units": "slots", + "width": 4 + } + } + ], + "links": [ + { + "id": "H1c0s5L2L", + "input": { + "nodeId": "Bk5TsqI2U", + "pinKey": "HJRLHWQw7" + }, + "output": { + "nodeId": "HJwCjcL28", + "pinKey": "BkQzLCurwJZ" + } + }, + { + "id": "HyHu2cLh8", + "input": { + "nodeId": "rkV_hc8hU", + "pinKey": "Hy_D4G0JOX" + }, + "output": { + "nodeId": "Bk5TsqI2U", + "pinKey": "Sk18BWmwX" + } + }, + { + "id": "Hysaj5I3U", + "input": { + "nodeId": "Bk5TsqI2U", + "pinKey": "Syb8BW7wm" + }, + "output": { + "nodeId": "rJM499I3L", + "pinKey": "r1ZqKlXPX" + } + }, + { + "id": "SydCj5Ln8", + "input": { + "nodeId": "HJwCjcL28", + "pinKey": "B1GfLR_SPk-" + }, + "output": { + "nodeId": "Bye0sqL3U", + "pinKey": "ByfGSDjQE" + } + }, + { + "id": "SyqOhq8hI", + "input": { + "nodeId": "S1Ddh5L2L", + "pinKey": "HkXK-dGob" + }, + "output": { + "nodeId": "rkV_hc8hU", + "pinKey": "BkvDEzR1Om" + } + } + ], + "nodes": [ + { + "id": "Bk5TsqI2U", + "position": { + "units": "slots", + "x": 9, + "y": 3 + }, + "type": "xod/datetime/add-seconds" + }, + { + "id": "Bye0sqL3U", + "position": { + "units": "slots", + "x": 10, + "y": 1 + }, + "size": { + "height": 1, + "units": "slots", + "width": 3 + }, + "type": "xod/debug/tweak-number" + }, + { + "boundLiterals": { + "SJ4zUC_BD1-": "3600" + }, + "id": "HJwCjcL28", + "position": { + "units": "slots", + "x": 10, + "y": 2 + }, + "type": "xod/core/multiply" + }, + { + "id": "S1Ddh5L2L", + "position": { + "units": "slots", + "x": 9, + "y": 6 + }, + "size": { + "height": 1, + "units": "slots", + "width": 4 + }, + "type": "xod/debug/watch" + }, + { + "boundLiterals": { + "r1f2FeXP7": "1", + "ryjoteXwm": "1970" + }, + "id": "rJM499I3L", + "position": { + "units": "slots", + "x": 9, + "y": 0 + }, + "type": "xod/datetime/datetime" + }, + { + "id": "rkV_hc8hU", + "position": { + "units": "slots", + "x": 9, + "y": 4 + }, + "type": "xod/datetime/format-timestamp" + } + ] +} diff --git a/workspace/welcome-to-xod/014-internet-tethering/patch.xodp b/workspace/welcome-to-xod/014-internet-tethering/patch.xodp new file mode 100644 index 000000000..d1505e589 --- /dev/null +++ b/workspace/welcome-to-xod/014-internet-tethering/patch.xodp @@ -0,0 +1,148 @@ +{ + "comments": [ + { + "content": "# Internet Tethering\n\nThere is a large class of applications known as IoT (Internet of Things) when the hardware connects to the Internet to send or receive data from some server. For example, log the temperature and moisture for smart greenhouses, get the current time, weather, send third-party service API request, and so on.\n\nIn this chapter, we are going to fetch the current date/time from the XOD Cloud API.\n\nThe `xod-cloud/basics/now` node sends a request to the XOD Cloud, parses the response, and outputs it as a `datetime` type value.\n\nThis node has an input pin `INET`. This pin has to be connected to an internet provider. The Internet can be provided:\n\n- by the controller board\n (such as ESP8266)\n- by an extension module\n (such as W5500 Ethernet Shield)\n- **by your PC**. This trick is known as Internet tethering and works in simulation and debug modes", + "id": "HyGHq2IhU", + "position": { + "units": "slots", + "x": 1, + "y": 0 + }, + "size": { + "height": 6, + "units": "slots", + "width": 7 + } + }, + { + "content": "Note, we’ve placed a `select` node here to get a reasonable value until we receive the result from the cloud. Otherwise, we would get a default datetime value, which is equal to `1970-01-01 00:00:00`, and it might be confusing.\n\n## Excercise\nUpdate the current datetime value by sending pulses.\n1. Place a `tweak-pulse` node.\n2. Link it to the `INIT` pin\n3. To make a value in the `watch` node properly, you need to provide the third possible value `\"Waiting pulse\"`. Drag the handle of the `select` node to the right to add one more pair of input pins\n4. Bind `\"Waiting pulse\"` and \"On Boot\" to the latest pair of pins.\n5. Link `tweak-pulse` to the `S2` pin\n6. Simulate the patch and send pulse using the `tweak-pulse` node.", + "id": "S1aXcWd6U", + "position": { + "units": "slots", + "x": 16, + "y": 1 + }, + "size": { + "height": 5, + "units": "slots", + "width": 7 + } + } + ], + "links": [ + { + "id": "Ska3H5DCL", + "input": { + "nodeId": "H1Bjn28h8", + "pinKey": "r1lFErc828" + }, + "output": { + "nodeId": "HyhhS5wR8", + "pinKey": "SyveJHHBL" + } + }, + { + "id": "r1Mpo-_TI", + "input": { + "nodeId": "SkxnjWOp8", + "pinKey": "S10qrR6UZ" + }, + "output": { + "nodeId": "H1v2hnL3L", + "pinKey": "BkvDEzR1Om" + } + }, + { + "id": "rJX6sWdpU", + "input": { + "nodeId": "SkxnjWOp8", + "pinKey": "rkmiHCaIZ" + }, + "output": { + "nodeId": "H1Bjn28h8", + "pinKey": "Sk0OelypI" + } + }, + { + "id": "ry9nn2Lh8", + "input": { + "nodeId": "H1v2hnL3L", + "pinKey": "Hy_D4G0JOX" + }, + "output": { + "nodeId": "H1Bjn28h8", + "pinKey": "ryFe8qI3U" + } + }, + { + "id": "ryH3oW_68", + "input": { + "nodeId": "B1an3hU3L", + "pinKey": "HkXK-dGob" + }, + "output": { + "nodeId": "SkxnjWOp8", + "pinKey": "S1yaHC6UW" + } + } + ], + "nodes": [ + { + "id": "B1an3hU3L", + "position": { + "units": "slots", + "x": 10, + "y": 4 + }, + "size": { + "height": 1, + "units": "slots", + "width": 5 + }, + "type": "xod/debug/watch" + }, + { + "boundLiterals": { + "HyF4Hq828": "On Boot" + }, + "id": "H1Bjn28h8", + "position": { + "units": "slots", + "x": 10, + "y": 1 + }, + "type": "xod-cloud/basics/now" + }, + { + "id": "H1v2hnL3L", + "position": { + "units": "slots", + "x": 10, + "y": 2 + }, + "type": "xod/datetime/format-timestamp" + }, + { + "id": "HyhhS5wR8", + "position": { + "units": "slots", + "x": 10, + "y": 0 + }, + "type": "xod/debug/tethering-inet" + }, + { + "boundLiterals": { + "rJUjrCTUb": "On Boot", + "rygjH06LW": "\"Fetching...\"" + }, + "id": "SkxnjWOp8", + "position": { + "units": "slots", + "x": 10, + "y": 3 + }, + "type": "xod/core/select" + } + ] +} diff --git a/workspace/welcome-to-xod/015-xod-cloud-feeds/patch.xodp b/workspace/welcome-to-xod/015-xod-cloud-feeds/patch.xodp new file mode 100644 index 000000000..f1fe73573 --- /dev/null +++ b/workspace/welcome-to-xod/015-xod-cloud-feeds/patch.xodp @@ -0,0 +1,127 @@ +{ + "comments": [ + { + "content": "Now we’re going to store data in the cloud. In one of the next sections of the tutorial, we’ll retrieve the data and react to it.\n\nYou can see a `cloud-store` node here. This node stores data to your private feed. The feed is log-like storage of your data. The name of the feed is a path, like a path in URL or your filesystem. For example, `bob/smart-home-project/room1/temperature`.\nThe `cloud-store` node prepends the username and project name automatically to the path. That's why we bound the `\"moisture\"` value to the `FEED` input instead of a full path.\n\nThe program is ready, but to make it work, you have to do a few things related to authorization.\n\n## Excercise\n\n1. Log in into your XOD account in the Account Pane (hit View → Toggle Account Pane).\n2. Open Project Preferences (hit Edit → Project Preferences). Ensure that the project has a name and click the \"Generate\" button next to the \"XOD Cloud API Key\" input.\n3. Run a simulation and change the value of a `tweak-number` node several times.\n4. Open the [feeds](https://xod.io/feeds/?utm_source=ide&utm_medium=ide_comment&utm_campaign=tutorial) page and check out the data stored in the feed named `YOUR_USERNAME/welcome-to-xod/moisture`.", + "id": "S1Xo6Npn8", + "position": { + "units": "slots", + "x": 14, + "y": 0 + }, + "size": { + "height": 7, + "units": "slots", + "width": 7 + } + }, + { + "content": "# XOD Cloud Feeds\n\nThe basic Internet-of-Things applications is mostly about collecting some data and storing it in the cloud, or reacting to the data changes.\n\nIt can improve a production process on factories, lower the defect rate, and so on. Also, it integrates into a life of ordinary people: smart fridges, homes, greenhouses, wearable electronics, etc.\n\nSome systems have their servers to collect the data. Still, for the individuals, maintaining such infrastructure is too complicated and expensive. Here comes the [XOD Cloud](https://xod.io/docs/guide/getting-started-with-feeds/?utm_source=ide&utm_medium=ide_comment&utm_campaign=tutorial) service. Using it you can store and retrieve any data.\n\nXOD provides the standard library called `xod-cloud/feeds` to work with cloud feeds easily. It has nodes to store and retrieve data.\n\nYou can see all your stored data at [https://xod.io/feeds/](https://xod.io/feeds/?utm_source=ide&utm_medium=ide_comment&utm_campaign=tutorial)", + "id": "SJ9QOpLnU", + "position": { + "units": "slots", + "x": 1, + "y": 0 + }, + "size": { + "height": 5, + "units": "slots", + "width": 7 + } + } + ], + "links": [ + { + "id": "BJQitEpnI", + "input": { + "nodeId": "HyMoFEThU", + "pinKey": "BkjI-COLb" + }, + "output": { + "nodeId": "Hyg5KV63I", + "pinKey": "ByfGSDjQE" + } + }, + { + "id": "BkB0-mRnL", + "input": { + "nodeId": "SyDrb703I", + "pinKey": "r1m2IKiY5r" + }, + "output": { + "nodeId": "HyMoFEThU", + "pinKey": "ByAIWR_UZ" + } + }, + { + "id": "HJ5BWXA2I", + "input": { + "nodeId": "SyDrb703I", + "pinKey": "rJfEHhF5r" + }, + "output": { + "nodeId": "Hyg5KV63I", + "pinKey": "ByfGSDjQE" + } + }, + { + "id": "SkKr-7ChI", + "input": { + "nodeId": "SyDrb703I", + "pinKey": "rJgh8tjF9r" + }, + "output": { + "nodeId": "ryCXuTIn8", + "pinKey": "SyveJHHBL" + } + } + ], + "nodes": [ + { + "id": "HyMoFEThU", + "position": { + "units": "slots", + "x": 12, + "y": 1 + }, + "type": "xod/core/pulse-on-change" + }, + { + "boundLiterals": { + "ByfGSDjQE": "1" + }, + "id": "Hyg5KV63I", + "position": { + "units": "slots", + "x": 11, + "y": 0 + }, + "size": { + "height": 1, + "units": "slots", + "width": 2 + }, + "type": "xod/debug/tweak-number" + }, + { + "boundLiterals": { + "ryZ28tst5B": "\"moisture\"" + }, + "id": "SyDrb703I", + "position": { + "units": "slots", + "x": 9, + "y": 2 + }, + "type": "xod-cloud/feeds/cloud-store" + }, + { + "id": "ryCXuTIn8", + "position": { + "units": "slots", + "x": 9, + "y": 0 + }, + "type": "xod/debug/tethering-inet" + } + ] +} diff --git a/workspace/welcome-to-xod/111-feed-messaging/patch.xodp b/workspace/welcome-to-xod/111-feed-messaging/patch.xodp new file mode 100644 index 000000000..d96828d07 --- /dev/null +++ b/workspace/welcome-to-xod/111-feed-messaging/patch.xodp @@ -0,0 +1,239 @@ +{ + "comments": [ + { + "content": "Now you got a remote analog gauge for the data that you send to the cloud. You can place it on your desktop and watch for the moisture in your greenhouse located far away.\n\nYou might build another device to switch a water pump in response to the same data feed changes. Moreover, you could send the status of the water pump to the cloud to see if the pump is working.", + "id": "SyoB37C3I", + "position": { + "units": "slots", + "x": 11, + "y": 5 + }, + "size": { + "height": 2, + "units": "slots", + "width": 8 + } + }, + { + "content": "# Feed Messaging\n\nIn this chapter, we’ll make an analog gauge for the data that is pushed to the cloud in the same way you already saw in one of the previous chapters.\n\nThe `xod-cloud/feeds` standard library provides nodes to retrieve the last value from your feed with different types: `cloud-boolean`, `cloud-string`, and `cloud-number`. Since we're sending number values, we pick `cloud-number`.\n\nOn the left side, nodes react to the data changes by rotating a servo. On the right side, you see nodes to update the value and check out how your servo responds.\n\nNote that on both sides, we named the feed as \"moisture\", they should match. Usually, the moisture is measured as a percentage. So we expect values in a range from 0.00 to 1.00. If you use another range, place the `map` node before the `VAL` input of a `servo` node.\n\n## Excercise\n\n1. Bind a proper `PORT` to the `servo` node\n2. Upload the program with the debug mode turned on.\n3. Update `tweak-number` value and check out how your servo responds.\n4. Place a `map` node between `cloud-number` and `servo` if needed.", + "id": "r1z3ULah8", + "position": { + "units": "slots", + "x": 0, + "y": 0 + }, + "size": { + "height": 7, + "units": "slots", + "width": 7 + } + }, + { + "content": "Use the `tweak-number` node to update the value.", + "id": "rJ8BqQR2L", + "position": { + "units": "slots", + "x": 15, + "y": 1 + }, + "size": { + "height": 1, + "units": "slots", + "width": 4 + } + } + ], + "links": [ + { + "id": "B1BWr57RhU", + "input": { + "nodeId": "BkM-rq702I", + "pinKey": "rJfEHhF5r" + }, + "output": { + "nodeId": "SJxbH97AnL", + "pinKey": "ByfGSDjQE" + } + }, + { + "id": "ByG9CqwRU", + "input": { + "nodeId": "Hk_Aq9DAU", + "pinKey": "r1bBAVNAh8" + }, + "output": { + "nodeId": "S1dnUITnL", + "pinKey": "SyveJHHBL" + } + }, + { + "id": "ByXbH5XR38", + "input": { + "nodeId": "BkWS5mCn8", + "pinKey": "BkjI-COLb" + }, + "output": { + "nodeId": "SJxbH97AnL", + "pinKey": "ByfGSDjQE" + } + }, + { + "id": "S1I-r5X0h8", + "input": { + "nodeId": "BkM-rq702I", + "pinKey": "r1m2IKiY5r" + }, + "output": { + "nodeId": "BkWS5mCn8", + "pinKey": "ByAIWR_UZ" + } + }, + { + "id": "S1_oC9PCI", + "input": { + "nodeId": "Hk_Aq9DAU", + "pinKey": "S1rCENRnL" + }, + "output": { + "nodeId": "rJPiAqPCI", + "pinKey": "ByHmL0uHPk-" + } + }, + { + "id": "SJtiRqwRL", + "input": { + "nodeId": "rJPiAqPCI", + "pinKey": "ryv7IRdSP1b" + }, + "output": { + "nodeId": "S1co57ChU", + "pinKey": "HJU8CE2lW" + } + }, + { + "id": "SkCt05wRL", + "input": { + "nodeId": "SySEqQA28", + "pinKey": "Bk5lexBtE" + }, + "output": { + "nodeId": "Hk_Aq9DAU", + "pinKey": "BJHJB4R2U" + } + }, + { + "id": "rJ4ZS57RhU", + "input": { + "nodeId": "BkM-rq702I", + "pinKey": "rJgh8tjF9r" + }, + "output": { + "nodeId": "Hy-WB9Q038", + "pinKey": "SyveJHHBL" + } + } + ], + "nodes": [ + { + "boundLiterals": { + "ryZ28tst5B": "\"moisture\"" + }, + "id": "BkM-rq702I", + "position": { + "units": "slots", + "x": 15, + "y": 4 + }, + "type": "xod-cloud/feeds/cloud-store" + }, + { + "id": "BkWS5mCn8", + "position": { + "units": "slots", + "x": 18, + "y": 3 + }, + "type": "xod/core/pulse-on-change" + }, + { + "boundLiterals": { + "H1GSAN40nI": "\"moisture\"" + }, + "id": "Hk_Aq9DAU", + "position": { + "units": "slots", + "x": 9, + "y": 3 + }, + "type": "xod-cloud/feeds/cloud-number" + }, + { + "id": "Hy-WB9Q038", + "position": { + "units": "slots", + "x": 15, + "y": 2 + }, + "type": "xod/debug/tethering-inet" + }, + { + "boundLiterals": { + "B13SCNhl-": "30" + }, + "id": "S1co57ChU", + "position": { + "units": "slots", + "x": 11, + "y": 1 + }, + "type": "xod/core/clock" + }, + { + "id": "S1dnUITnL", + "position": { + "units": "slots", + "x": 9, + "y": 1 + }, + "type": "xod/debug/tethering-inet" + }, + { + "boundLiterals": { + "ByfGSDjQE": "0.25" + }, + "id": "SJxbH97AnL", + "position": { + "units": "slots", + "x": 17, + "y": 2 + }, + "size": { + "height": 1, + "units": "slots", + "width": 2 + }, + "type": "xod/debug/tweak-number" + }, + { + "id": "SySEqQA28", + "position": { + "units": "slots", + "x": 8, + "y": 4 + }, + "type": "xod-dev/servo/servo" + }, + { + "boundLiterals": { + "ByU7LRuSPkW": "On Boot" + }, + "id": "rJPiAqPCI", + "position": { + "units": "slots", + "x": 11, + "y": 2 + }, + "type": "xod/core/any" + } + ] +} diff --git a/workspace/welcome-to-xod/112-standalone-internet/patch.xodp b/workspace/welcome-to-xod/112-standalone-internet/patch.xodp new file mode 100644 index 000000000..d77b85807 --- /dev/null +++ b/workspace/welcome-to-xod/112-standalone-internet/patch.xodp @@ -0,0 +1,114 @@ +{ + "comments": [ + { + "content": "Here are these nodes:\n\n- `xod-dev/esp8266-mcu/connect`\n- `xod-dev/esp8266/connect`\n- `xod-dev/w5500/ethernet-shield`\n\n## Excercise\n\n1. Replace the `tethering-inet` node with a suitable one from the list above.\n2. Bind the appropriate values to the node inputs such as the name of your WiFi access point and password.\n3. Bind the `PORT` value to `servo` node.\n4. Upload the patch without debug mode.\n\nNote that you need to log in and generate a XOD Cloud API key for the project if you haven't done it before (hit Edit → Project Preferences).\n\nThe servo rotates to the angle that corresponds to the latest \"moisture\" value. Now you can open the chapter `015-xod-cloud` again, run the simulation and control your gauge from XOD IDE over the cloud. Or you can make another device, which updates this value automatically.\n\n---\n\nIn some cases, you might need to make an advanced configuration of the connected module or ethernet-shield. Check out examples in the library or read an article about [ethernet-shield advanced configuration](https://xod.io/docs/guide/w5500-advanced/?utm_source=ide&utm_medium=ide_comment&utm_campaign=tutorial).", + "id": "S1CmLCCh8", + "position": { + "units": "slots", + "x": 15, + "y": 0 + }, + "size": { + "height": 7, + "units": "slots", + "width": 7 + } + }, + { + "content": "# Stand-alone Internet\n\nIt's time to make your device autonomous. \n\nHere is the program from the previous chapter. The program has a `tethering-inet` node that depends on PC and works only in the debug mode. To make a stand-alone device, replace it with another node that provides the internet using some hardware module, shield, or the native microcontroller features.\n\nFor such purposes XOD has a few standard libraries:\n\n- [`xod-dev/esp8266-mcu`](https://xod.io/libs/xod-dev/esp8266-mcu/?utm_source=ide&utm_medium=ide_comment&utm_campaign=tutorial) — if you run the program on ESP8266,\n- [`xod-dev/esp8266`](https://xod.io/libs/xod-dev/esp8266/?utm_source=ide&utm_medium=ide_comment&utm_campaign=tutorial) — if you run the program on the microcontroller without onboard WiFi module, but using an ESP8266 as an AT command modem,\n- [`xod-dev/w5500`](https://xod.io/libs/xod-dev/w5500/?utm_source=ide&utm_medium=ide_comment&utm_campaign=tutorial) — if you have an ethernet shield based on W5500 chipset.\n\nEach of the libraries has a set of some low-level networking nodes. But for the current case, you only need the internet provider node.", + "id": "rkMW2eVC28", + "position": { + "units": "slots", + "x": 0, + "y": 0 + }, + "size": { + "height": 6, + "units": "slots", + "width": 7 + } + } + ], + "links": [ + { + "id": "BJlOvpA2U", + "input": { + "nodeId": "r1KwvpChI", + "pinKey": "r1bBAVNAh8" + }, + "output": { + "nodeId": "BJZ3lNAh8", + "pinKey": "SyveJHHBL" + } + }, + { + "id": "SknPwaChL", + "input": { + "nodeId": "Bkg-heN028", + "pinKey": "Bk5lexBtE" + }, + "output": { + "nodeId": "r1KwvpChI", + "pinKey": "BJHJB4R2U" + } + }, + { + "id": "SyUuwTRnL", + "input": { + "nodeId": "r1KwvpChI", + "pinKey": "S1rCENRnL" + }, + "output": { + "nodeId": "HJbZ2eN03U", + "pinKey": "HJU8CE2lW" + } + } + ], + "nodes": [ + { + "id": "BJZ3lNAh8", + "position": { + "units": "slots", + "x": 9, + "y": 0 + }, + "type": "xod/debug/tethering-inet" + }, + { + "boundLiterals": { + "BkXK1eBYV": "D5" + }, + "id": "Bkg-heN028", + "position": { + "units": "slots", + "x": 8, + "y": 3 + }, + "type": "xod-dev/servo/servo" + }, + { + "boundLiterals": { + "B13SCNhl-": "5" + }, + "id": "HJbZ2eN03U", + "position": { + "units": "slots", + "x": 11, + "y": 1 + }, + "type": "xod/core/clock" + }, + { + "boundLiterals": { + "H1GSAN40nI": "\"moisture\"" + }, + "id": "r1KwvpChI", + "position": { + "units": "slots", + "x": 9, + "y": 2 + }, + "type": "xod-cloud/feeds/cloud-number" + } + ] +} From 0bec628b6ef43bae461bb764808fa8046e915c54 Mon Sep 17 00:00:00 2001 From: Kirill Shumilov Date: Thu, 11 Jun 2020 12:47:20 +0300 Subject: [PATCH 08/10] feat(stdlib): add nodes `cloud-boolean` and `cloud-string` into `xod-cloud/feeds` --- .../xod-cloud/feeds/cloud-boolean/patch.xodp | 130 +++++++++++++ .../xod-cloud/feeds/cloud-string/patch.xodp | 177 ++++++++++++++++++ 2 files changed, 307 insertions(+) create mode 100644 workspace/__lib__/xod-cloud/feeds/cloud-boolean/patch.xodp create mode 100644 workspace/__lib__/xod-cloud/feeds/cloud-string/patch.xodp diff --git a/workspace/__lib__/xod-cloud/feeds/cloud-boolean/patch.xodp b/workspace/__lib__/xod-cloud/feeds/cloud-boolean/patch.xodp new file mode 100644 index 000000000..ff7276b5c --- /dev/null +++ b/workspace/__lib__/xod-cloud/feeds/cloud-boolean/patch.xodp @@ -0,0 +1,130 @@ +{ + "description": "Gets a boolean value from the feed.", + "links": [ + { + "id": "Bk9or_J6U", + "input": { + "nodeId": "B1nqSu1aL", + "pinKey": "B1z-efOk6L" + }, + "output": { + "nodeId": "ryMGird1a8", + "pinKey": "__out__" + } + }, + { + "id": "HyPiHuJTU", + "input": { + "nodeId": "B1nqSu1aL", + "pinKey": "SyRbeMuyTI" + }, + "output": { + "nodeId": "r1VMird16I", + "pinKey": "__out__" + } + }, + { + "id": "HyYjBu1aU", + "input": { + "nodeId": "HJbzoSd1TL", + "pinKey": "__in__" + }, + "output": { + "nodeId": "B1nqSu1aL", + "pinKey": "Hk7ZxGd1TU" + } + }, + { + "id": "SysiH_kT8", + "input": { + "nodeId": "B1nqSu1aL", + "pinKey": "BJhZez_yTU" + }, + "output": { + "nodeId": "S1xGsHOJp8", + "pinKey": "__out__" + } + }, + { + "id": "ryGGUuk6U", + "input": { + "nodeId": "SJyzI_ypL", + "pinKey": "__in__" + }, + "output": { + "nodeId": "B1nqSu1aL", + "pinKey": "Hy6y8_k68" + } + } + ], + "nodes": [ + { + "id": "B1nqSu1aL", + "position": { + "units": "slots", + "x": 1, + "y": 1 + }, + "type": "@/cloud-boolean-custom" + }, + { + "description": "Pulses when the value is successfully stored", + "id": "HJbzoSd1TL", + "label": "DONE", + "position": { + "units": "slots", + "x": 2, + "y": 2 + }, + "type": "xod/patch-nodes/output-pulse" + }, + { + "boundLiterals": { + "__out__": "\"my-value\"" + }, + "description": "Feed path starting from the project name. The full feed path will be `//`", + "id": "S1xGsHOJp8", + "label": "FEED", + "position": { + "units": "slots", + "x": 5, + "y": 0 + }, + "type": "xod/patch-nodes/input-string" + }, + { + "id": "SJyzI_ypL", + "position": { + "units": "slots", + "x": 1, + "y": 2 + }, + "type": "xod/patch-nodes/output-boolean" + }, + { + "description": "An established internet connection", + "id": "r1VMird16I", + "label": "INET", + "position": { + "units": "slots", + "x": 1, + "y": 0 + }, + "type": "xod/patch-nodes/input-t1" + }, + { + "boundLiterals": { + "__out__": "On Boot" + }, + "description": "Request the value from the cloud", + "id": "ryMGird1a8", + "label": "DO", + "position": { + "units": "slots", + "x": 6, + "y": 0 + }, + "type": "xod/patch-nodes/input-pulse" + } + ] +} diff --git a/workspace/__lib__/xod-cloud/feeds/cloud-string/patch.xodp b/workspace/__lib__/xod-cloud/feeds/cloud-string/patch.xodp new file mode 100644 index 000000000..69d5581a3 --- /dev/null +++ b/workspace/__lib__/xod-cloud/feeds/cloud-string/patch.xodp @@ -0,0 +1,177 @@ +{ + "description": "Gets a string value from the feed.", + "links": [ + { + "id": "HklTWOJT8", + "input": { + "nodeId": "H1-UnbukaU", + "pinKey": "__in__" + }, + "output": { + "nodeId": "HJqhZ_JTU", + "pinKey": "SkQn4Z_J6U" + } + }, + { + "id": "HyITZ_JaL", + "input": { + "nodeId": "SJEpWOkaU", + "pinKey": "__in__" + }, + "output": { + "nodeId": "HJqhZ_JTU", + "pinKey": "ByIcWO1TU" + } + }, + { + "id": "SJ-C-ukTU", + "input": { + "nodeId": "H1Cpbuya8", + "pinKey": "__in__" + }, + "output": { + "nodeId": "HJqhZ_JTU", + "pinKey": "rJKwbd16L" + } + }, + { + "id": "SkR2-OkpL", + "input": { + "nodeId": "HJqhZ_JTU", + "pinKey": "Syz3EWOkp8" + }, + "output": { + "nodeId": "HyG82Zd1TL", + "pinKey": "__out__" + } + }, + { + "id": "SyXjDOJ6U", + "input": { + "nodeId": "HJqhZ_JTU", + "pinKey": "HJSqD_yp8" + }, + "output": { + "nodeId": "BJZjPOya8", + "pinKey": "__out__" + } + }, + { + "id": "Syo2ZdJaI", + "input": { + "nodeId": "HJqhZ_JTU", + "pinKey": "ByCnVZu1aL" + }, + "output": { + "nodeId": "BkV82bu1a8", + "pinKey": "__out__" + } + }, + { + "id": "rya3-OJaI", + "input": { + "nodeId": "HJqhZ_JTU", + "pinKey": "ryh34Z_1aU" + }, + "output": { + "nodeId": "ryeU2-d16I", + "pinKey": "__out__" + } + } + ], + "nodes": [ + { + "boundLiterals": { + "__out__": "16" + }, + "description": "The capacity of the string buffer. Defines the maximum length. Must be a constant value. Any changes during program execution will be ignored.", + "id": "BJZjPOya8", + "label": "CAP", + "position": { + "units": "slots", + "x": 1, + "y": 0 + }, + "type": "xod/patch-nodes/input-number" + }, + { + "description": "An established internet connection", + "id": "BkV82bu1a8", + "label": "INET", + "position": { + "units": "slots", + "x": 0, + "y": 0 + }, + "type": "xod/patch-nodes/input-t1" + }, + { + "description": "Pulses when the value is successfully stored", + "id": "H1-UnbukaU", + "label": "DONE", + "position": { + "units": "slots", + "x": 2, + "y": 2 + }, + "type": "xod/patch-nodes/output-pulse" + }, + { + "description": "Pulses when string reached maximum length and pushed character was ignored", + "id": "H1Cpbuya8", + "label": "FULL", + "position": { + "units": "slots", + "x": 1, + "y": 2 + }, + "type": "xod/patch-nodes/output-pulse" + }, + { + "id": "HJqhZ_JTU", + "position": { + "units": "slots", + "x": 0, + "y": 1 + }, + "type": "@/cloud-string-custom" + }, + { + "boundLiterals": { + "__out__": "On Boot" + }, + "description": "Request the value from the cloud", + "id": "HyG82Zd1TL", + "label": "DO", + "position": { + "units": "slots", + "x": 5, + "y": 0 + }, + "type": "xod/patch-nodes/input-pulse" + }, + { + "id": "SJEpWOkaU", + "position": { + "units": "slots", + "x": 0, + "y": 2 + }, + "type": "xod/patch-nodes/output-string" + }, + { + "boundLiterals": { + "__out__": "\"my-value\"" + }, + "description": "Feed path starting from the project name. The full feed path will be `//`", + "id": "ryeU2-d16I", + "label": "FEED", + "position": { + "units": "slots", + "x": 4, + "y": 0 + }, + "type": "xod/patch-nodes/input-string" + } + ] +} From 4723c97809a9e95105749bd4c56f18e16ffeadf6 Mon Sep 17 00:00:00 2001 From: Kirill Shumilov Date: Fri, 19 Jun 2020 15:21:27 +0300 Subject: [PATCH 09/10] fix(stdlib): do not try to open a new tcp connection in tethering-inet while it has already opened connection --- workspace/__lib__/xod/debug/open-tcp/patch.cpp | 4 ++++ workspace/__lib__/xod/debug/tethering-inet/patch.cpp | 2 ++ 2 files changed, 6 insertions(+) diff --git a/workspace/__lib__/xod/debug/open-tcp/patch.cpp b/workspace/__lib__/xod/debug/open-tcp/patch.cpp index fb08a1d29..d91f8cafe 100644 --- a/workspace/__lib__/xod/debug/open-tcp/patch.cpp +++ b/workspace/__lib__/xod/debug/open-tcp/patch.cpp @@ -13,6 +13,10 @@ void evaluate(Context ctx) { return; auto inet = getValue(ctx); + + // Do nothing if TCP connection is already opened + if (inet->isConnected()) return; + auto host = getValue(ctx); uint32_t port = (uint32_t)getValue(ctx); diff --git a/workspace/__lib__/xod/debug/tethering-inet/patch.cpp b/workspace/__lib__/xod/debug/tethering-inet/patch.cpp index d8dab6cc3..715ba0ad9 100644 --- a/workspace/__lib__/xod/debug/tethering-inet/patch.cpp +++ b/workspace/__lib__/xod/debug/tethering-inet/patch.cpp @@ -280,6 +280,8 @@ class TetheringInternet { // TODO: MUX printPrefix(); writeCmd(CIPCLOSE, EOL); + _connected = false; + _pkgSize = 0; return readCmd(OK, ERROR) == 1; } }; From d622a439d1154636e02d1b4d7b52f47b6d3f68a1 Mon Sep 17 00:00:00 2001 From: Kirill Shumilov Date: Fri, 19 Jun 2020 19:34:43 +0300 Subject: [PATCH 10/10] fix(xod-client, xod-client-electron): clear the queued chunks of a response data on connection close --- .../src/debugger/tetheringInetMiddleware.js | 14 +++++++++++++- packages/xod-client/src/debugger/actionTypes.js | 2 ++ packages/xod-client/src/debugger/actions.js | 4 ++++ packages/xod-client/src/debugger/reducer.js | 3 +++ 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/packages/xod-client-electron/src/debugger/tetheringInetMiddleware.js b/packages/xod-client-electron/src/debugger/tetheringInetMiddleware.js index f4c5ccff3..cec90c77f 100644 --- a/packages/xod-client-electron/src/debugger/tetheringInetMiddleware.js +++ b/packages/xod-client-electron/src/debugger/tetheringInetMiddleware.js @@ -73,6 +73,15 @@ const createListener = (dispatch, transmit, nodeId) => const isReadOkResponse = R.startsWith(ACK); +// In case that the connection is closed before than all request has been received +// there is no reason to continue sending the response data. +const clearQueueOnCloseConnection = R.curry((dispatch, command) => + R.when( + R.equals('AT+CIPCLOSE'), + R.compose(dispatch, client.tetheringInetClearChunks) + )(command) +); + export default ({ getState, dispatch }) => next => action => { const state = getState(); const result = next(action); @@ -86,7 +95,10 @@ export default ({ getState, dispatch }) => next => action => { const worker = action.payload.worker; const transmit = createTransmitter(dispatch, worker.sendToWasm); const listener = createListener(dispatch, transmit, nodeId); - const write = AtNet.create(listener); + const write = R.compose( + AtNet.create(listener), + R.tap(clearQueueOnCloseConnection(dispatch)) + ); dispatch( client.tetheringInetCreated( action.payload.tetheringInetNodeId, diff --git a/packages/xod-client/src/debugger/actionTypes.js b/packages/xod-client/src/debugger/actionTypes.js index d7704053a..dfdf558dc 100644 --- a/packages/xod-client/src/debugger/actionTypes.js +++ b/packages/xod-client/src/debugger/actionTypes.js @@ -31,3 +31,5 @@ export const TETHERING_INET_CREATED = 'TETHERING_INET_CREATED'; export const TETHERING_INET_CHUNKS_ADDED = 'TETHERING_INET_CHUNKS_ADDED'; export const TETHERING_INET_CHUNK_SENT = 'TETHERING_INET_CHUNK_SENT'; + +export const TETHERING_INET_CLEAR_CHUNKS = 'TETHERING_INET_CLEAR_CHUNKS'; diff --git a/packages/xod-client/src/debugger/actions.js b/packages/xod-client/src/debugger/actions.js index 1709db8df..b63801ba9 100644 --- a/packages/xod-client/src/debugger/actions.js +++ b/packages/xod-client/src/debugger/actions.js @@ -106,3 +106,7 @@ export const tetheringInetChunkSent = () => (dispatch, getState) => { }); return maybeProp(0, chunksToSend); }; + +export const tetheringInetClearChunks = () => ({ + type: AT.TETHERING_INET_CLEAR_CHUNKS, +}); diff --git a/packages/xod-client/src/debugger/reducer.js b/packages/xod-client/src/debugger/reducer.js index 16e83845b..161288ff6 100644 --- a/packages/xod-client/src/debugger/reducer.js +++ b/packages/xod-client/src/debugger/reducer.js @@ -23,6 +23,7 @@ import { TETHERING_INET_CREATED, TETHERING_INET_CHUNKS_ADDED, TETHERING_INET_CHUNK_SENT, + TETHERING_INET_CLEAR_CHUNKS, } from './actionTypes'; import * as EAT from '../editor/actionTypes'; @@ -531,6 +532,8 @@ export default (state = initialState, action) => { R.tail, state ); + case TETHERING_INET_CLEAR_CHUNKS: + return R.assocPath(['tetheringInet', 'chunksToSend'], [], state); case EAT.TABTEST_RUN_REQUESTED: return R.compose(