From 4176098a55ef266e3eacb728d69c033079c4b46f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crist=C3=B3bal=20Contreras=20Rubio?= Date: Thu, 23 May 2024 18:49:50 +0200 Subject: [PATCH] SBG-ECOM-NODERED: v0.0.1 with the minimum to be publish --- .github/workflows/sbg-ecom-nodered.yml | 59 ++ packages/sbg-ecom-nodered/.gitignore | 144 +++++ packages/sbg-ecom-nodered/Dockerfile | 13 + packages/sbg-ecom-nodered/LICENSE | 21 + packages/sbg-ecom-nodered/README.md | 101 ++++ packages/sbg-ecom-nodered/docker-compose.yml | 14 + .../examples/sbg-ecom-nodered-examples.json | 379 ++++++++++++ .../sbg-ecom-nodered/examples/sbg-raw.bin | Bin 0 -> 11776 bytes packages/sbg-ecom-nodered/manual_tests.sh | 5 + packages/sbg-ecom-nodered/package.json | 48 ++ .../src/icons/cma-logo-blue.png | Bin 0 -> 15621 bytes .../src/icons/cma-logo-white.png | Bin 0 -> 15531 bytes packages/sbg-ecom-nodered/src/parser.html | 166 ++++++ packages/sbg-ecom-nodered/src/parser.js | 153 +++++ .../tests/nodered/components/package.json | 49 ++ .../components/src/icons/cma-logo-blue.png | Bin 0 -> 15621 bytes .../components/src/icons/cma-logo-white.png | Bin 0 -> 15531 bytes .../tests/nodered/components/src/parser.html | 166 ++++++ .../tests/nodered/components/src/parser.js | 153 +++++ .../tests/nodered/data/flows.json | 379 ++++++++++++ .../tests/nodered/data/settings.js | 542 ++++++++++++++++++ .../tests/nodered/tests/sbg-raw.bin | Bin 0 -> 11776 bytes packages/sbg-ecom-nodered/vitest.config.ts | 13 + 23 files changed, 2405 insertions(+) create mode 100644 .github/workflows/sbg-ecom-nodered.yml create mode 100755 packages/sbg-ecom-nodered/.gitignore create mode 100755 packages/sbg-ecom-nodered/Dockerfile create mode 100755 packages/sbg-ecom-nodered/LICENSE create mode 100755 packages/sbg-ecom-nodered/README.md create mode 100755 packages/sbg-ecom-nodered/docker-compose.yml create mode 100755 packages/sbg-ecom-nodered/examples/sbg-ecom-nodered-examples.json create mode 100644 packages/sbg-ecom-nodered/examples/sbg-raw.bin create mode 100755 packages/sbg-ecom-nodered/manual_tests.sh create mode 100755 packages/sbg-ecom-nodered/package.json create mode 100644 packages/sbg-ecom-nodered/src/icons/cma-logo-blue.png create mode 100644 packages/sbg-ecom-nodered/src/icons/cma-logo-white.png create mode 100755 packages/sbg-ecom-nodered/src/parser.html create mode 100755 packages/sbg-ecom-nodered/src/parser.js create mode 100755 packages/sbg-ecom-nodered/tests/nodered/components/package.json create mode 100755 packages/sbg-ecom-nodered/tests/nodered/components/src/icons/cma-logo-blue.png create mode 100755 packages/sbg-ecom-nodered/tests/nodered/components/src/icons/cma-logo-white.png create mode 100755 packages/sbg-ecom-nodered/tests/nodered/components/src/parser.html create mode 100755 packages/sbg-ecom-nodered/tests/nodered/components/src/parser.js create mode 100644 packages/sbg-ecom-nodered/tests/nodered/data/flows.json create mode 100755 packages/sbg-ecom-nodered/tests/nodered/data/settings.js create mode 100644 packages/sbg-ecom-nodered/tests/nodered/tests/sbg-raw.bin create mode 100755 packages/sbg-ecom-nodered/vitest.config.ts diff --git a/.github/workflows/sbg-ecom-nodered.yml b/.github/workflows/sbg-ecom-nodered.yml new file mode 100644 index 0000000..0cdf025 --- /dev/null +++ b/.github/workflows/sbg-ecom-nodered.yml @@ -0,0 +1,59 @@ +name: sbg-ecom-nodered + +on: + workflow_dispatch: + push: + paths: + - packages/sbg-ecom-nodered/** + +jobs: + # test: + # name: ๐Ÿงช Test + # runs-on: ubuntu-latest + + # strategy: + # matrix: + # node-version: [18.x, 20.x] + + # steps: + # - name: ๐Ÿ‘ Checkout + # uses: actions/checkout@v3 + + # - name: โ‡๏ธ Setup node.js + # uses: actions/setup-node@v3 + # with: + # node-version: ${{ matrix.node-version }} + # cache: 'npm' + + # - name: ๐Ÿ“ฅ Install Dependencies + # run: npm install + + # - name: ๐Ÿง‘โ€๐Ÿ”ฌ Tests + # run: "npm run norsub-emru-nodered:test" + + publish: + name: ๐Ÿš€ Publish + runs-on: ubuntu-latest + # needs: test + if: github.ref == 'refs/heads/main' + + steps: + - name: ๐Ÿ‘ Checkout + uses: actions/checkout@v3 + + - name: โ‡๏ธ Setup node.js + uses: actions/setup-node@v3 + with: + node-version: 20 + registry-url: 'https://registry.npmjs.org' + + - name: ๐Ÿ“ฅ Install Dependencies + run: npm install + + # - name: ๐Ÿ› ๏ธ Build + # run: "npm run norsub-emru-nodered:build" + + - name: ๐Ÿš€ Publish to npm + run: "npm publish --access public --workspace=@coremarine/sbg-ecom-nodered" + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/packages/sbg-ecom-nodered/.gitignore b/packages/sbg-ecom-nodered/.gitignore new file mode 100755 index 0000000..600077b --- /dev/null +++ b/packages/sbg-ecom-nodered/.gitignore @@ -0,0 +1,144 @@ +# IDEs +.vscode +.idea + +# OSX +.DS_Store + +# Node-Red +.config.*.json +.config.*.json.backup +.flows* +flows_cred.json +tests/nodered/data/package.json + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* diff --git a/packages/sbg-ecom-nodered/Dockerfile b/packages/sbg-ecom-nodered/Dockerfile new file mode 100755 index 0000000..58879d2 --- /dev/null +++ b/packages/sbg-ecom-nodered/Dockerfile @@ -0,0 +1,13 @@ +FROM nodered/node-red:latest-18 + +USER root +RUN mkdir -m 777 /components && chown node-red:node-red /components\ + && mkdir -m 777 /config && chown node-red:node-red /config \ + && mkdir -m 777 /db && chown node-red:node-red /db \ + && mkdir -m 777 /static && chown node-red:node-red /static \ + && mkdir -m 777 /tests && chown node-red:node-red /tests +COPY --chown=node-red:node-red --chmod=777 tests/nodered/components/ /components/ + +USER node-red + +RUN npm i --production @coremarine/sbg-ecom /components diff --git a/packages/sbg-ecom-nodered/LICENSE b/packages/sbg-ecom-nodered/LICENSE new file mode 100755 index 0000000..c779757 --- /dev/null +++ b/packages/sbg-ecom-nodered/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 CoreMarine + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/sbg-ecom-nodered/README.md b/packages/sbg-ecom-nodered/README.md new file mode 100755 index 0000000..10a604e --- /dev/null +++ b/packages/sbg-ecom-nodered/README.md @@ -0,0 +1,101 @@ +# NMEA-Parser-NodeRED + +![npm (scoped)](https://img.shields.io/npm/v/%40coremarine/sbg-ecom-nodered) +[![publish](https://github.com/core-marine-dev/devices/actions/workflows/sbg-ecom-nodered.yml/badge.svg)](https://github.com/core-marine-dev/devices/actions/workflows/sbg-ecom-nodered.yml) +![npm](https://img.shields.io/npm/dy/%40coremarine/sbg-ecom-nodered) + +sbg-ecom + +Node-Red component to read NMEA 0183 sentences. It is a wrapper of [@coremarine/nmea-parser](https://www.npmjs.com/package/@coremarine/nmea-parser) (check it docs). + +## Input + +NMEA component uses 5 properties to work: + +- `payload` is the main property with NMEA content. +- `protocols`, `sentence`, `memory` and `fake` are optionals. + +| Input property | Description | +| :--------------------- | :------------------------------------------------------------------------------------- | +| `payload` (string) | NMEA ASCII content (important, it is an *ASCII* string, not other encoding). | +| *`memory`* (object) | Object to check or enabled / disabled parser memory state (look details below). | +| *`protocols`* (object) | Object to get or set the protocols supported and their sentences (look details below). | +| *`sentence`* (string) | Sentence ID to get if it is supported and its info (look details below). | +| *`fake`* (string) | Sentence ID to get a full fake NMEA-like sentence if it is supported. | + +## Output + +Each input proerty would be responded in the same output property + +| Output property | Description | +| :--------------------- | :----------------------------------------------------------------------------------------------------------------------------- | +| payload (array) | It gives you the same parsing output that the CoreMarine NMEA Parser (an array of object with the info of each NMEA sentence). | +| *`memory`* (object) | Response to the *memory* input (look details below). | +| *`protocols`* (object) | Response to the *protocols* input (look details below). | +| *`sentence`* (string) | Response to the *sentence* input (look details below). | +| *`fake`* (string) | Response to the *fake* input (look details below). | + +## Details + +NMEA parser translate NMEA ASCII string data into a JavaScript objects (one for each +NMEA 0183 sentence). Each time it receives data from payload input, it gives the parsed sentences to payload output. + +It just a wrapper of the npm library [@coremarine/nmea-parser](https://www.npmjs.com/package/@coremarine/nmea-parser) (take a look on it). + +To interact with the *memory* | *protocols* | *sentence* API is through the `memory` | `protocols` | `sentence` property: + +- If you request something in `msg.memory` | `msg.protocols` | `msg.sentence` input +- The response will be in `msg.memory` | `msg.protocols` | `msg.sentence` output + +### Memory + +It is enabled by default: + +- memory enabled: Every time you inject data, it's attached to the internal data. +- memory disabled: Every time you inject data, it clears internal data and add new one. + +Internally it has a buffer with a max number of characters + +| Input | Output | +| :------------------------------------------------------: | :-----------------------------------------------------------: | +| `memory`: { `command`: `"set"`, `payload`: **boolean** } | `memory`: { `memory`: **boolean**, `characters`: **number** } | +| `memory`: { `command`: `"get"` } | `memory`: { `memory`: **boolean**, `characters`: **number** } | + +### Protocols + +The parser can be feeded or expanded to understand more nmea sentences, standard or propietary. +To do that it should be passed an object with the property `command` equal to `"set"` and one this three properties: + +1. `file`: It's the string file path to the protocols YAML file. +2. `content`: It's the string content of the protocols YAML file. +3. `protocols`: It's the JS object after parsing the protocols YAML file. + +If you send more of them, parser only will read one (`file` upper other, `content` upper `protocols`) + +If you just want to know what are the known or supported sentences, you just need the command `get`. + +| Input | Output | +| :----------------------------------------------------------: | :--------------------: | +| `protocols`: { `command`: `"set"`, `file`: **string** } | `protocols`: **array** | +| `protocols`: { `command`: `"set"`, `content`: **string** } | `protocols`: **array** | +| `protocols`: { `command`: `"set"`, `protocols`: **object** } | `protocols`: **array** | +| `protocols`: { `command`: `"get"` } | `protocols`: **array** | + +### Sentence + +If you want to know if a sentence is known / supported, you need to send the sentence id. +Response will be an `object` with the whole info or `null` if it's unknown / not supported yet. + +| Input | Output | +| :--------------------: | :------------------------------: | +| `sentence`: **string** | `sentence`: **object** \| `null` | + +### Fake + +If you want to get a NMEA-like sentence, maybe just to do some tests, you need to send the sentence id. +Response will be a `string` with the whole ASCII sentence or `null` if it's unknown / not supported yet. +This fake sentence is correct in terms of NMEA requirements but each field has garbage. + +| Input | Output | +| :----------------: | :--------------------------: | +| `fake`: **string** | `fake`: **string** \| `null` | diff --git a/packages/sbg-ecom-nodered/docker-compose.yml b/packages/sbg-ecom-nodered/docker-compose.yml new file mode 100755 index 0000000..6f8920b --- /dev/null +++ b/packages/sbg-ecom-nodered/docker-compose.yml @@ -0,0 +1,14 @@ +# version: '3' +name: sbg-ecom + +services: + nodered: + build: + context: . + dockerfile: Dockerfile + ports: + - 1880:1880 + volumes: + # Node-Red working files + - ./tests/nodered/data:/data + - ./tests/nodered/tests:/tests \ No newline at end of file diff --git a/packages/sbg-ecom-nodered/examples/sbg-ecom-nodered-examples.json b/packages/sbg-ecom-nodered/examples/sbg-ecom-nodered-examples.json new file mode 100755 index 0000000..8c0339f --- /dev/null +++ b/packages/sbg-ecom-nodered/examples/sbg-ecom-nodered-examples.json @@ -0,0 +1,379 @@ +[ + { + "id": "86f1271d07a48b44", + "type": "tab", + "label": "SBGEcom Parser Examples", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "9283b11f486aa6af", + "type": "group", + "z": "86f1271d07a48b44", + "name": "Flow Errors", + "style": { + "stroke": "#000000", + "label": true, + "color": "#000000" + }, + "nodes": [ + "3dcdbb2ff53d1ac2", + "cd7a546b03381262" + ], + "x": 34, + "y": 19, + "w": 352, + "h": 82 + }, + { + "id": "fa79e06be881de74", + "type": "group", + "z": "86f1271d07a48b44", + "name": "Examples", + "style": { + "stroke": "#000000", + "label": true, + "color": "#000000" + }, + "nodes": [ + "bf1bf2211a0a99f4", + "0d643452dedfda51", + "bab379433f7607f5", + "2a2312ddbf6c1d4c", + "1b7de497daf8146e", + "b2dd2fc884f2b756", + "0866325a71bf54c8", + "50ec56828023ecac", + "cf83530668c8884e", + "95faf8f169dbc837", + "1a18d2d87afbf6c9", + "eb57049a15b736b8", + "8c98d96f36590d9d" + ], + "x": 34, + "y": 139, + "w": 672, + "h": 382 + }, + { + "id": "3dcdbb2ff53d1ac2", + "type": "catch", + "z": "86f1271d07a48b44", + "g": "9283b11f486aa6af", + "name": "ERRORS", + "scope": null, + "uncaught": false, + "x": 120, + "y": 60, + "wires": [ + [ + "cd7a546b03381262" + ] + ] + }, + { + "id": "cd7a546b03381262", + "type": "debug", + "z": "86f1271d07a48b44", + "g": "9283b11f486aa6af", + "name": "ERRORS", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 280, + "y": 60, + "wires": [] + }, + { + "id": "bf1bf2211a0a99f4", + "type": "debug", + "z": "86f1271d07a48b44", + "g": "fa79e06be881de74", + "name": "Payload", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "payload", + "targetType": "msg", + "statusVal": "", + "statusType": "auto", + "x": 580, + "y": 260, + "wires": [] + }, + { + "id": "0d643452dedfda51", + "type": "inject", + "z": "86f1271d07a48b44", + "g": "fa79e06be881de74", + "name": "Memory ON", + "props": [ + { + "p": "memory", + "v": "{\"command\":\"set\",\"payload\":true}", + "vt": "json" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 150, + "y": 280, + "wires": [ + [ + "2a2312ddbf6c1d4c" + ] + ] + }, + { + "id": "bab379433f7607f5", + "type": "inject", + "z": "86f1271d07a48b44", + "g": "fa79e06be881de74", + "name": "Memory OFF", + "props": [ + { + "p": "memory", + "v": "{\"command\":\"set\",\"payload\":false}", + "vt": "json" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 150, + "y": 240, + "wires": [ + [ + "2a2312ddbf6c1d4c" + ] + ] + }, + { + "id": "2a2312ddbf6c1d4c", + "type": "cma-sbg-ecom", + "z": "86f1271d07a48b44", + "g": "fa79e06be881de74", + "name": "", + "memory": true, + "firmware": "2.3", + "x": 420, + "y": 340, + "wires": [ + [ + "bf1bf2211a0a99f4", + "8c98d96f36590d9d" + ] + ] + }, + { + "id": "1b7de497daf8146e", + "type": "inject", + "z": "86f1271d07a48b44", + "g": "fa79e06be881de74", + "name": "Send data", + "props": [], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 140, + "y": 180, + "wires": [ + [ + "b2dd2fc884f2b756" + ] + ] + }, + { + "id": "b2dd2fc884f2b756", + "type": "file in", + "z": "86f1271d07a48b44", + "g": "fa79e06be881de74", + "name": "", + "filename": "/tests/sbg-raw.bin", + "filenameType": "str", + "format": "", + "chunk": false, + "sendError": false, + "encoding": "none", + "allProps": false, + "x": 330, + "y": 180, + "wires": [ + [ + "2a2312ddbf6c1d4c" + ] + ] + }, + { + "id": "0866325a71bf54c8", + "type": "inject", + "z": "86f1271d07a48b44", + "g": "fa79e06be881de74", + "name": "Get All Available Firmwares", + "props": [ + { + "p": "firmwares", + "v": "{}", + "vt": "json" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 190, + "y": 340, + "wires": [ + [ + "2a2312ddbf6c1d4c" + ] + ] + }, + { + "id": "50ec56828023ecac", + "type": "inject", + "z": "86f1271d07a48b44", + "g": "fa79e06be881de74", + "name": "Set Firmware 2.3", + "props": [ + { + "p": "firmware", + "v": "{\"command\":\"set\",\"payload\":\"2.3\"}", + "vt": "json" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 160, + "y": 440, + "wires": [ + [ + "2a2312ddbf6c1d4c" + ] + ] + }, + { + "id": "cf83530668c8884e", + "type": "inject", + "z": "86f1271d07a48b44", + "g": "fa79e06be881de74", + "name": "Set Firmware 3.2", + "props": [ + { + "p": "firmware", + "v": "{\"command\":\"set\",\"payload\":\"2.3\"}", + "vt": "json" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 160, + "y": 480, + "wires": [ + [ + "2a2312ddbf6c1d4c" + ] + ] + }, + { + "id": "95faf8f169dbc837", + "type": "inject", + "z": "86f1271d07a48b44", + "g": "fa79e06be881de74", + "name": "Get Firmware", + "props": [ + { + "p": "firmware", + "v": "{\"command\":\"get\"}", + "vt": "json" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 150, + "y": 400, + "wires": [ + [ + "2a2312ddbf6c1d4c" + ] + ] + }, + { + "id": "1a18d2d87afbf6c9", + "type": "debug", + "z": "86f1271d07a48b44", + "g": "fa79e06be881de74", + "name": "Memory", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "memory", + "targetType": "msg", + "statusVal": "", + "statusType": "auto", + "x": 580, + "y": 300, + "wires": [] + }, + { + "id": "eb57049a15b736b8", + "type": "debug", + "z": "86f1271d07a48b44", + "g": "fa79e06be881de74", + "name": "Firmwares", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "firmwares", + "targetType": "msg", + "statusVal": "", + "statusType": "auto", + "x": 590, + "y": 340, + "wires": [] + }, + { + "id": "8c98d96f36590d9d", + "type": "debug", + "z": "86f1271d07a48b44", + "g": "fa79e06be881de74", + "name": "Firmware", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "firmware", + "targetType": "msg", + "statusVal": "", + "statusType": "auto", + "x": 580, + "y": 380, + "wires": [] + } +] \ No newline at end of file diff --git a/packages/sbg-ecom-nodered/examples/sbg-raw.bin b/packages/sbg-ecom-nodered/examples/sbg-raw.bin new file mode 100644 index 0000000000000000000000000000000000000000..828bd11fa6094cdcf23d4e428531ec82c15a1f3c GIT binary patch literal 11776 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 literal 0 HcmV?d00001 diff --git a/packages/sbg-ecom-nodered/manual_tests.sh b/packages/sbg-ecom-nodered/manual_tests.sh new file mode 100755 index 0000000..2094d7d --- /dev/null +++ b/packages/sbg-ecom-nodered/manual_tests.sh @@ -0,0 +1,5 @@ +mkdir -p tests/nodered/components +cp -r package.json src tests/nodered/components +chmod -R 777 tests/nodered/components + +docker compose down && docker compose up --build \ No newline at end of file diff --git a/packages/sbg-ecom-nodered/package.json b/packages/sbg-ecom-nodered/package.json new file mode 100755 index 0000000..ddda59c --- /dev/null +++ b/packages/sbg-ecom-nodered/package.json @@ -0,0 +1,48 @@ +{ + "name": "@coremarine/sbg-ecom-nodered", + "version": "0.0.1", + "author": "CoreMarine", + "license": "MIT", + "description": "sbg-ecom", + "homepage": "https://github.com/core-marine-dev/devices/tree/main/packages/sbg-ecom-nodered", + "repository": { + "type": "git", + "url": "git+https://github.com/core-marine-dev/devices.git" + }, + "bugs": { + "url": "https://github.com/core-marine-dev/devices/issues" + }, + "keywords": [ + "sbg-ecom", + "sbg", + "gnss", + "gps", + "mru", + "imu", + "binary", + "protocol", + "parser" + ], + "engines": { + "node": ">=18.0.0" + }, + "node-red": { + "version": ">=3.0.0", + "nodes": { + "cma-sbg-ecom": "src/parser.js" + } + }, + "main": "index.js", + "files": [ + "src", + "examples" + ], + "scripts": { + "docker": "sh manual_tests.sh", + "test": "mocha \"tests/**/*.test.js\"", + "test:vitest": "vitest" + }, + "dependencies": { + "@coremarine/sbg-ecom": ">=0.0.1" + } +} diff --git a/packages/sbg-ecom-nodered/src/icons/cma-logo-blue.png b/packages/sbg-ecom-nodered/src/icons/cma-logo-blue.png new file mode 100644 index 0000000000000000000000000000000000000000..c33c2d871d8580a09d4c7baf38afbf6fffef006c GIT binary patch literal 15621 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 AjQ{`u literal 0 HcmV?d00001 diff --git a/packages/sbg-ecom-nodered/src/icons/cma-logo-white.png b/packages/sbg-ecom-nodered/src/icons/cma-logo-white.png new file mode 100644 index 0000000000000000000000000000000000000000..8fc7b25bdb2ee4a8249280696b235b8974129b35 GIT binary patch literal 15531 zcmbumcU%+7wl*BPiUuMIiZla)C4iD35Gh*-U_?Oay@&}!IwABDL?nWMqFYR)7(}WR zMWjPi+^7TyD1y|8N-sf>Uf#id?m72<=brEVW@gQ-GP7pZdRA^;G%?(>OMDju z0@;H-hcSadxE8j5cJPCimd`^85D0G-!NMlc#`pr-&DUGW^@{IhoKlFlALxfbG<8D! zT-`izfijnI?gSq#_-t(>T!wH(3vR7yeA3uY59dKR7Z!js4>PfF3-ff-xB}PF-lZ9W z1`~MW0$pW7yuEyg=nyUV?|ISS_w8n7xXkY%fu34$8{>;IdcFZT8C4}!rIT>&T{4;h zSMX>vjKM#M!6z-aM_`~IT3I$V z%5G2b_Z%1;(Jg@B7fA5+k=dTp^|CK1Pzw$R{WAZU92Y|P*X%yTe~1qhp}gIrd`ju0 z@_!#5NWlMx;oCj`Hr&s{H_(^p;p_KL0shAl|Lp!ZLZH6?og~E7?|&O?Z2bQ}+}rzq zh(Qe04+4t#hf@CsPye+5(IV6jr)-8J`jP_NaQZU4kAKbfuZ{~iANPOj z+2+oRv~6BX9|Dj^F_K?3P{8txNPw!%Y zFP`89`iN$Rx-wXOz0;>OPM=m(QTlrYU^q0OCE!Cbu7O~b%1ITJ;z?D-Q)(8cQ0S8? z=u;{uz`y^{*6-2aJX~=Nbp5}L-`>?Snt;OC7=4aF4D<~M{oVBURyW7_|NZIjk6wh| zdt655x24gpZre)Ig8K#dULm>RuKX4YO!s#$(H9>W>>7YO>kf>p1wV_&6M#BHWx(+v zxclG&WK?8Slu$~4Yxkd2!5%m;b6`RY3Q58*l-@ zmni?!nSc-fbVoQJ;DZ8yv)LK;HV8Ph7y>ZOznKIAIeLe5r~L%x(!OS$8#fOe78Mm$ zc2$+txhj4LCwDLB)CU*jJbv&NO}cbxFz3D1m*eNX*6lcAWtN}M!;aau(|R6_Y9dur zH7beiqfxV3dExDR*6PK0W)0W7D~htHgBGH)M&~18YThW=qcerH)t>(T-ImiEnc@nA ztLb)K?HiuPbJq)Wjbl0ag@^8Q?s1s3Cuizp`{}va{$G)()lE2e1_KMiZk)Xt2*S(ihWp;hMa56dTtihGV zZ*G(*+e=5H*$UD3)4vz0Ozt~ra|F9furxokAoF(q&CJ_(a@h-8zRt$pA^8>qBD_oG z-i?d88>b_@zbrQ2@s5_%n-+1vpIE8Z+fjG3!LlO^`UuC zRsRzLCtz1A%%d^puODXZAJ)<}{|Iqxm=IrFq?@)?K8@f>=x|@OpT5rpZjGIO=WK}( zh@i;!4;O@%egFcIfnYIbEke?#2ZF2cxX{_T**&{@VzaYhh;#cd-s};+PPcK>dzL+y zk40da8rXfT2M-Rop)x%#V^1dNqAu$gyyD(*&G8;w5_9p7Fl8QQ_4QQkB%4pE-gFk_%R}u8F7YV{V_twxU~pA zoY-|36&_pweWY@Td+8~ZZZg02IP3IN=p*q-3xSK&a7zK!HATsH;T~wsmxdp7rIm$N zH){wov-ELJkJK^2$U4ojwH8>-=O(xC9K^!h&quS$hGTXjDbshJvzl9C8yY3(p2q(o z4Y*#SI`^Ll1sy$ypJ|ziu7-rNmeSJtE99m6WO4MAG=a!y4c%^9h*!$JIBh4Xg$>fi z?!j+02kYW<-~3(|_JJAx4LuMUG!ELIZ?}JQq7n*HZpUex*jos&vYFXliVIQm2c!=R zMy9_kgg)Y{Jq*W_-VfaL-}rG#TUT^d-P>0355d!S?+`KHpAH(CfBm~Pv}~yxF_UFo zmnPrh7I7W1;Q!NQw$wJ6CP`mPYhK=AJ0^RVIth7bJ<7TUcy#dUkeU>SHL|~z@ARvj z5VkvMI7UmXlLeSTX&n0-K)QUNxm zr=yJ3{H7yx%W_|h?84@JkMvH#NKMWBwb}k_OD|Y!?QYR>fZ=ycQjB8}(W9g8dr4eR zg_eK^8|W_t;g<#Gx@S)w+E+Kb!YJmOEqcEq$vy>Gjs$iHd0)KMmPnzBd1Cr?%_k<* z+PP$1=qYb}y0~6=xF;{vs~*hcF<|IQS1}!=d#b_4p1%HiN&6WGbkx2W<=*okPCKHV zf98^;Zeozx*Kqr>jbI_REtuU=bd@u0FZqYaCELP3buM@WXo~GlH{yoc;C*-T2{~760yUi_&AYFse-B3Pi&~3 z3g&ZikktL?Mi=TkQN-f`ukjPA6+HMNBvXW+sVkk&>=*BOhK`rd7F;S*TyPDE!24K& z;jVO{G!d5@j|FkPal2`|+xPJN$f@G`z$AHmW)J45C&+(047>DfYI0hID8jD$u$%T^ zo*Zx3^n5~whA{PwOYyVcv&b()R?(Z`~0~zUK_IPO@bOT4>C^g@B4WbEkPG* zNi1W=e}7SOPvZ}a!v%A0@f(Vq#r{V&V>}(&g+YIS(H3IL{=uj2iq4Q1`{`U9K@EvU zAuoHdWY^oDQ-dZtG_`GJce>D7aiK3c;Agm}95VDo zx_@*|1)Nr7DpAKnb4C$h*AA|nBvqqo(~Sj3t8+%vcXYT>t7Vm%H89;gOG%W6g|Sc1 z<4a7-3Ac>mq3y}Axw~N39xxo!>S{Z`(KjJMOOUOx8-aMgd|XKMI6gRjYiaX2Yi+Wc zfdrf#hZaFk3PirkUkT^uq;C^O@13Lv8CIBkEUJFyXu{!9wvv~PRftIT)9tC8xl$4+ zlZCM!Q4;i}k9|Ow6ALA2K$q#pYFT%?hqd-8y!(|JH;ANG@8O7bX`oaiYwiu?J*8ze zzGD^_>3KvU7NiIYMG-ryjDVetv(7&^wN=##=F|SpTOBo**d4k?)ZO@-*lmR+t8ulcxUH3EV8%WJ1-2Tnqy3GMn5Cylb#ppeXq zlDg(gD-)1J*60-Np#t}sbv%m}`o8{+3Q>){V;!CJY7ypdMxw;MV>Ux{irVM}_WV;) zu%QBIwq^NI^l_y0j`eiBS;CEJ3)+*@<>+_1FWQf1@q1m$&^Hf;aUM{>4i+AuruCo6 zueT=cxW8f(@v;;LW#PBHNYK`%zZkEmgy6v2&i8zJg?b*Nuj5Bp6A%&Lhnh1{qen@% z0HHiGYnQ}L9j~OfSlF{j5(WE?=?v+!7-d~R@Z85Vb#$G5k^ZFPFm(mOMlO>M-aVY; z6~7SNK`Z8osL^sSkVPaXd(2`bxq4NmCp}vX1u^hcW1t_U}F8>_UdaS z^UpYD=p&aXlw}-X>;tpa?^w^N8u5_A$@=bq>rO|J(p(bBIBf&N-Nj5U_^?;M8R^!{ z9*NJHA1#`6l{-s#myG-OlAc1JLQm@JZPpTgo#t=&%3MM_1t{O9F6AD4tNBtr;i?1w zx(}w`Lh_2Z3XzAc#)vE`&u^Mz_`v*0q}$K@uWN%7rOi2lm_N1l{bGxR4BUqoTGB>W zIRkO_YA4aaU3{ZgwO5Eg9ftOi1_y@6DM-3LF!7k&B#>=&HE|>6v`xd ztFVo3vRuiGs7)KnYuTzc?=<0Gk#WLz2c#rZM2hs7X0>~V+Y5>LNNwJATTH*5@)^gl3I;M90Nbt4Ge*+(; zb{$@oLkbCGT4m_f|FUOqL9!N4r^T7zeT<2rk=?^bCmJPXhZTO0k~Ssow6wc53-P5; z%!^_z#HWueG3yNRo3eiJ`_-beC+@GT>o=v4ORYvP&Q9-2zfGNOV}@JA7pT<0!oov0 zsu==gQa(01*`b6$3d043hD&2HlEE}Bk@z09B)W>?a)F7^EU8D>}+wkOU%bL z_)Wj0W|g+lU-jG@k=UwOOxF>Ae1PsgqQu~0ICa^g)LY2j%~7*H&w5n{O)txh%C&w{ ziwV|mI@NVH*Sk!1fq9D=VTYIEkx0UojH|y>ajpwWS~3Oi5}9fJ@}bpJ)N1SSKGJRe zB{9#XW6{u7%DVqsf0S1@#J);@;>wG)Cs|zm<>*BIX$4f@izt%ET8R+;`k+$Rsu`P? zwx)2uI(K?jasEAF$tc>I1l=?Ejja5UnGpT{_Wji9jUDxon6F0|_T*L|wPsuHm)Z5) z2^qaq>LExTM5weayF*=PypX_z`p}Ey^(OA+0 z)$uDpxvPwF!ufS7!||#JwsOr6Q}+zrbl}Q}Az7!S?Qn$;SAz)=yBS@h9-S)^H`t~U zfhfy~oZj7EkGdD=Zq5DBu<1$H*}opuql4wyqSOi6WXvqL;mgu2{ifoII|;k$>kSu= z-WOXg31Jnk4NAbI^P#8YsVk$~uYhx&{`*^#eJl5`D<2=}Vdk*y(#wGeGnnq z_i!xo#qN-6eUCqTEM3^rHo0vc?FdQVl@3k+9Hl9#9-W%fteDS2&O0HLC-*0Y6WKm@ zcPWsXbPSuEE#eQ9Gb403qg@&~J8NU`neRU6M~7h?kVB@T)M_<9XWCoa8P(=A!Dwzcr@?-_3r9-k`@P;8BY5knmX9i*tC`~7B9tIU?B55k5@poiZv>&dyscqZL<#!3)nqxNyHM|(q%WQT~qB7d$7`GW!7yows&0*6Hy65LV0*H*PvsD zUg5}*;G_Yen2Z6@ilJU_s}!D~r)}{4bE&lk({}71_d~ZToZqDJbX&ULDYO|AFW0$A zDF-h)75MN42YnM+Jl*rDwm`&l^mX|e5r!BLXn$RN$tm=qko5B2_+v;l-Y9O(Y;+<@ zZ&0s$%t1(VNJYAYQpFvj?Wac)CEP~@CbfFX4(EV3V+lna7UD>P{%(BVh-q>MZ{^eQ z;YPBM)#z>f+wd{*L^rZl1jgH;cl2WlZ>Cv>K22qo?zvA1;^ak50dfurRDt&r%3HMN z#tfbv2m87+G6z1a%Z_6xcG>0-p0iW~eUmA(*6|mMDeBPW`3Z?mlo>Lw(YByqMyQVcK!A_q*bmjnh zTFdtR3y#qzW0?O=&INV?=#T>)sZUU{^T@*3{66?_AUhN_gzS_7N=&uZZ+g~s_>&OK ze>Z0WFp&cq6E=XTMSA(p@ZpaPF0hBOWh_-*X`Vsw^sfKq!`1=zPW<8KIZ^A&-5z9X zt!Pj?veq2~uC{Z6-$8SQ2wBW_#O~>0_*fj{CJ;C7IjhS$kH<8TQUo^U0r>E77iC7C z+$ST^n$bCVM?;<*%c>7ERHpJRa?#GoV)gBCq!bmuRc2U?6 zm(w5fTE|GKaU~@+un-fBgp(wOn?iZx5#&M4DKP<3=~oUQE16x#U~?o|{ipi8lD228 zE>-JJP1*=9h-8M5(4RloX9-lW-*#*w)rjnv0m&=zRQND`qrIR=4-rUu%g0dCrsXzJ zC|O*!5HVm}hOV_*y5Q7Q_Nj@7L37j$|LI^7Ij-cYJL_I`OLbvdFYa>iUyi*NOkL|I zA_S%K+Kz;<;sF*;tl!iz4iRX%BH#M1U-6>qj_IYJN{q_Fa*uS-x_qEDpv2l*;Ewz; zcnNnV-?}?VG$|#n#I{d*`3=Qyr|}-MwfYS-c$6Z<)7~+Q$l=xk9c)EDr~R-kpbgre z%!p%t!evhW`}PcVC9_lo(>^}k#8W*j;KN8%(FaGT4E;CmbkE*4{>*)_p<*c9(xY)H zYxlB8Zte%&Zd7DeE;CZw`mrbsYy;k?i(oX4?rEpZ2ZEtA3xPW|kF-SZLj5FmoN@oQ#|X+G&d8Ph@d0!mn{1f%>N?h z3h4mh9ULw@EW&W}NY)}0BLa(CRoJsJd6*{KF4vq>gp}$$$Sn8zSv$|~uT|{s&XcXH zo+Vf)BZKL-r-OhWosbi|-*GjPKjZ~YiKK^-;L#NKJ9N1i?9D$Nd8Q7*l!?O+KPgV1 zT2XOvrny-=xeJy*X!ByJ!;$ zyvb`^FcBM3G(J#jKsUIE^~=OwU?Y<*S&o6}hE*We2A#;kAiF#dtr%(b=C z%Nc}xUx{O~{zo`?7sD0@@%TlXXo=Qmv$FXhgC^9c!hXXTfz5F(A=3VOGT^zv!x&*0 za#YqIf$R#2w-tZf_ZGzna9$_^OEYLXS}CUA)zOqbxs0Boga`_6Dk zyFeRw=IktI#eWlLE22)+N4|CcaHRPB+SF=Vj5oQGyIa(-^SaI0M&<5h^)h|Ty7_jT zc+PA|zsVRjCq-MEly0834R6<-t<;P0mK|1w`ClR(z;1}Z#Ppjy$=)&TmZKf7ZO1ki zaI|7$X9-xIRs5Y#(I8mBOz9#0XHIm5qM}8^8YK+o5i9eu!%aX#Hx%F|6v`;qna*_L zClS#w9f_S&`(W*Xt_QH?!Z2{DxpSZS`q-!5g&y4Z3Zt>Hg-9<5e0)!3aKWzPh2CKB+ZI$V#qF zwK8RJcqLwSiH6m;5I);)-A>8GPCR7x9|#fQ@VmSjR(HeG#n1vFI(`>14%U(esiLyT zS*|+qWg;8)*8i_}y2>0LVCFR0;m<$_6c%LLTBG(xb7?+PZ+l=fh7363x5MvIdy0{G zA~OQTL9_QWA``yt&WO{-4e>#FwWWWb=A2#B&|r2P>c{52VRbzm-SicXp%9azVegna za}-(0?<82atIF9w{qQrE!q^U4$8y@h+=bN72xNC&b@wLPWeHHZ(3Lyq816A3%IhCS zq<%7@uAFp{X1`@XD+pmNy3XXgHcrDJ{dOnk@Ox&fttMAcrK9D z{PH$b4qJ4a`jD#~l4(+I%N)2WLV7(WxDiO>*4eEt5BEW|$zo~o%zj8uTrN9{%ggp* zK67l>Mi{NR#ph7m)^qg~Il?uS`L8J1C3lu4GML`n)uNW+XgWwELF z!^rN(p}S{}F-)c>H=odR-TmUC#9La{)Y%Aya%?Jl@jWT!dorKSy)X0iN((K7%$-|@ zjboy9;7Y|wa@dKx%>ErAD#q11F(Y4=*6!c1d*HNhwH4JKlf|1}^?Fj*a40ngd)07G zDEHXnv~`F#2$4_r_68QReEHjW+P){hjjUO!KZ5A+izSf@~yA;nsmbP0jf)w>1f7ouvdNf2!8u*MSrFfFAEWaVIgrgu6gv%=eA zO*`d6O~wHXr8W9Wfsm@1w~!{gkU7u3i^67_ueQL#+Cw>5nq2#_jUPMeM>Ut_j8jMN zZ3bK)BuYi3%D*R`j~=)}UwZgoa~gGXl{__}^VRxpulU@R1X1kSKM6^*%41#AdX6UN zoc&UVCW}rzCy`qU%{^Yddb_PPq`JaW&;?A+i8H2g`Bj^i3-kfpzn!StxW| z3l%<3<842(L2|_OSDCB{C3miQwlHr^2&b+VX~hG7OFG6tpV*8I8`oy=0Nqbi2=Hvf zdVICJ5esyVf+sfdt47Yy%t>9H#*-A$_Sj3EmqVcAmGiEl^sVQh#kY9^k{Z@ZJlD9f z_rBO_HAw@-WmL#>ZbG&F@J5i5x~_DB;gu1+?Wwbv5$f!f#{j?*VghhR?pNyL`OPz8 zfQpaN`TQu2SLi%e@N4zsAs=p~YcE-{mk)A^K49!#98o$cOVI8m-iRCY9epVowYEdD zZfY>NG10!@JT0r3oCIQzOKtVjVkbmvM82)IXT3Pm8b5k#v$nogk}i}eke9Qlo9PqOf|tCyv?{Eb2Mp=Nap;J4H*Bh?+<5b0$=)>G|A6se3ALI) z+JPPTlPbg$v<<)2>bcvGy%AxwZ0q2KH9!|JPoJ?&X|BS??I#>nO*#u-jNY&Y2@MQT zR!lLu*)sn2C#)&M@<{yUq`0Wles89pdnByybm%Oc+6JTiB~KJf6XSJLDE2XT-Kpoy z=R27WrReK9Gw+zcV$wi98IvB^my4*h?JB$s5~MfQxZ1&CC@|05*$<*T`C${{pq1sA z$*n_B2(i5S{VoqVWFfryhOV2>Dpaj5v&=rCaQu-RDS7JhUmwb~pg zgrq`rXU_p7;#AR;hhU@xberVfDB0B(XIL5#%3}8KR`)FQM|q|sQnIY#Z=>u1y25!3 zyg)wi_|;&+t|V4FSJasT?|`x+*+vE%`_1g;1tY`__EYy$_p4!bt(Isws5*v#b6D46r{`l|0^(siUV&GlEQ~;!w_C|Q) zB;3b#AljkN)VJA0{no_5{^b^Mz;Y)_$+Z^otft~QtL5HZ8+{_Xvu8rQ@!9}=&3W&c zGTjYKWf9?Nyyfp57bW4>`u%yn>}km0wwJT06R>IAj-QXS*F0DEc;0#x9ROyT zmw#4z$!hktXPa)zOHt$L1B`u=Xm~kP_Mz3*>ONJWBYj;}vzy!Au&J~t_MF`VkaJMq zUu6iep|>|-b7K`7xz$Q&_R+|ynVofjvmE`EMw=16(|ORBEIv*)v%d(mt+X)nc)|g) zZP8i~I~w*rQj4uZ>qx&bj&P}^R6PSP&+7NgJ>qQZ}TH} zLj2YqG7pkCFd>s_RjOqm)U^NW4WEM?9pXkSQ3)tYSRH@(=BE=zI!*6rt?4rF-PJIC9jC@Fha);yoVpEWLV?D(4erIg}(!@KBk5#^_+w z1H+FfaY=Q~_@R9TrRauD#ta3q)zL1`C4MN;{WRfuujD7_8x`rISW&x?vUe>S)aoOC zy_dD)!=@1~d6cRuH04w9^fyBD*Ub^PmpDxNGnP(We)DaROX-jCW=dg^W{trl;ez&F zx3QDkI8xi?4-)d_7hlDQEK5w3N|Kc;h{xqx&G9~e%s=RK1NhUY?ApK%5F#nQ3Bs|#9ciAy1QReh|qy&YTh(Oy>C6e>2@v4Xyc_2r-Hd) zYe(Qa!NgZGNe^!tBeK5l*zjS5Rt2QrKO+?aG8smdI_^;i+5qw-#v_!`v_X8p-cg?+ zvE+MqHA4KlB>5Y7@^+ogIX_*P(CkW`Oy2Z1!$C!ymUWP`rpWU{E~#18^#JYsJ5z)5 zq^=xb`>|uXY(E`SgFFQ3th=k%@7BeeU>vw5Q19Cd&h{Ko2N@95>FE+evkP^yP5ab) zmH1;`t!Y$y*3;RU`FD0-j2Yk!nFtmocrGEgP-RXeQIZL_J&3mNuIGqI(s^EZc0}Pi zv#evwv^mwxer2S>X1xOGEWYF}Re<$0(}U`1*?<}c(R5v7rJ$+;}L>qlYdzt*vnk3!dhAgGWcqrfWCM-kzg=tl=q9@ zd;{+l+!r>A8q$j`hqf*;)p~!ZJZbZ2RA}T{R|HdzW_&~tAG{h?riNOxEnLb8jcNR& z25d)ET0wt;C9bz9DVlF8#mL@svyJ!VO^SW)ioE&OP9)qXcZFa@E8RnG(cnWrP(i->qFDU5`_CXi#5Y_up zr;@}^Bp|ELK%?ov8Nk3!-&V`TJ4FyU!&# z1I%?yZB_gW7izUXUJ6s*Re&qOu1wngslg0M{0J~0X`V*4mZdKC07T*(^3Y~?m+L2K zYV}S|8e`J$^+Wl|W`;=b6PEksk?{NOBOl3c+&3D;;~vJulA~`?hzaHSpfUi-E@l)# zM%_HbGeMFu{l}rUIu@78{7Lrs{@LP7Re$2Ui-HZCj)9paK^;YF`FG{FajqyW=M;*2 z>#A|lu1HTB)_BsYuF*g?Mwxpyfs$nze<_36AA_&{EC$LX*aO^NhhTZ_t4T&tx=9rC znCPMq-=y=9aGqxOk!}^@@o?dyT9x_t)D;pt&t`;{6kU9jcvPIub7kZPs^#lI>G4>D z@io-a7acK}^*;BGeJ@7uM|#Yp=oF|YgK|Qbc}msu;ntR2k}^nV(|Kkd%2SPNOK5o? zCn@OWpf(Hup%_XpG3Mf7q+~+1bSWd*8n1 zJ3i%d@Z`eX7oEl+)RiObP>`hFFXzY0v1FfPizWAazL1?W0%pJ9o^AordCz zmN%YrM#gs=mpAwhCFgew%&5k9M-mKr?YV`TpJb?d2^cgP5XajFdn#1op`u}viHtPx!byFRs%+4dR;c&%yn{{d2WyX<}1r*vjzX*Av1;AHV4OM($S6MPHXAEHvDm25M5&+L( z#fv>-x`QICM@_`gpumW49ZP~@J3Z=;!P`op&rWA3FMK}B7~NjoVDutQ@y|1*VsV2` zBg?XEwJuvZ?Bh94c1mqj!N%$Oqk*6dPNF9bpLG?RntLoJvhQtM7+oz6DhxB^nk{ZS zj1{k2!ZZaJ>M;#Vch&z2VlRV-bk3{QW8hIHJl|ET>sy%-p~1Sj;eG@g8=%GcsqN$6 zU#knMFg}vitVeIl?P&ub<#^X&(d@LiLG*3Bh!{3i{;ObMgld)QxHr8r1y&~x3XBrv z3YJWGHm#kdF4_M%CVu#r_J0V6Vw|vD0s1b&+Oia)iU1GH{b(=rfyo zWgx+_1gBv_A~k1l1=vj&l*=5z&?^^tk_(}Su@gzMF+7EO7e2V`(t`VNIq8-!mdIf} z1GG7*FVFD1p4=8yj3=C@-d^~RR20%Ere1b9bwcJYDt}uD>93pPsX1NYZkY8dbW_fr z5|+IH_ZFyFOZ}v=B?SW|FQ@jzA{K&N$!c6f0FuK_+P>>;syM*calv zy&*o;E5HqYE&t31hO=VNcO90)niG$fMUyDDha9)}6G(^auN=X?3E<@vE;{HOe|%zl zJHSGeIQ84B-PC}F_=G1*XI%Pi52N{8t8?4?Cvnl7*8I_6jq=k&5HL}~o5`OJV7}BB zE(*VatU^%7K%#@XvnLEG#+Pl1`5@6UcZ`FTWKQqcHi;5%P~I1gQ|c$7QLb9UCjG9n zH4I%}{iafn^Ba}h1fC?AF*VCtGUo(hVLzscib@+&E(IF1D{dic!H1uM+Ki9t&z+X<-*v&q_~D%Fn>*sMcuj*)-eFa`4sdUs+=Lm+rRh`V@^{ zdEA4QcXGb09Bb8@7c7chh>6oSoK6TZ^3xN;(&D~(WFn>=%*B=@g`Ie2AET2%sWiAg`jHP19RptqTGwX(IE+9i*TWvo~wPy5h06!Wz2-qcW9o1o8&`P_KB|Y0(BD% zCWf{*qGXVIt65272~OyU z`EzCh2tFqH8=ws6i-Wxy!+Q2-f%e1jOifK+y=d zG7vtbF(L@Da4?b5-l16!*=)Q0k#gs~l>$&J z0kZO)GxN1-oMy(JxBha3Qzdz!7nb6*ot>I>mG{98!nUAOkoBkN6gfqPX^bR%m;ow^ zPJ&E-Fz~4Sns@L9`2yE-w9m1nV-yU519QDX4>rIck|>psaMsixa#+V-o**uq5`&f8 z_yQ9R12rIb7>fX02j)Bu@UTEkL>`(l^GbSV+FA zz>Jgt)zlY&p&tjKKux3iyPLiPIC?NZ({@hrufy2iWK!|t$7#(SpfC!cVK4BaVM3Uu z=agk3mqToTp~xk@P9uBwf_}^R4p1hgwHMaNl_^vwT$Qh$oa0)vqvs6V33xb*_>O+i z`*F~Ii@VihLkCz;{2osXfV4m)unokR>No9&&DpsGv!^CBQ$cV?Tl*e;0A_6!-|^aJ zOsiYFvO$vL!{C#WYi%~85t~8rrUmJMVse}|xWV)=Q>Mg&n=OE!U$4_VluBo%VLrmD z5YbgKrs)f8E`s*M&9tOVw&1P_caX0_eTKQD!Cg>qeGwyZwp^z55Vgn@#icy`!>Tfw zvXwxwFXAc4j4SD@NU4dG=(#o$YAKd+yXJ=k&5f8yS*}WXM9>$lnURCvH)t{>By7Yn zgc4=3Zc98gH~+*%+kho+Rt7+4ixuOKt9Acr^qf7HG@lP5`N*EGB!(ebvG3RCMr+A)8!mKDC;0F!N{Ck3F^(GJNX5;Z zS5>?r0%ZhD-C=m!Q)o`qGggHR%pZ$cSL9rzeR-*KG+FLfmyky?J>H<{jO=Ua)Cw8V z8qp^Mi5uTwb8;@>Z0DF0iEdcOU_Q=S+GumuCn>!dY>ECemMTDa%`of7I4-oftI5Zb zf7oK(#k z5j@E`E3Us1Vg9!MQb`ZuO3YyX$NXgcT=3e$Jr8sHgZZ;n9=;IABEQa;GsNJ-!^4_; zUFb!6@Zm~Ee2kF$NNmiIKql7|w7*>Cp~0*jtz|r($2o~2m@t1X_%gldZm-BlBhOYQ zb+Y5>k*z@5wV{__+_x+2vPDw*q3rxgQ1##x4%d1fxnYU-dHpkBh^NZhRdY|XDx=b4 z*ZLutf0Vxz!3mUln1pB7PdBWEp=w`E^G)$;N>$mrYW`~8!$={2Bl~g>CGL z03?rIhP3%Q4>@+t5)^(6WSkLQ{~)c#`}y&)&FY9cf?agp{(g*kjZvR-`;Tw?x9iq) z1{WtMGw#V7w{HoIEcjg?old$5z7ht-* + + + + + + + diff --git a/packages/sbg-ecom-nodered/src/parser.js b/packages/sbg-ecom-nodered/src/parser.js new file mode 100755 index 0000000..c3607ce --- /dev/null +++ b/packages/sbg-ecom-nodered/src/parser.js @@ -0,0 +1,153 @@ +const { SBGParser: Parser } = require('@coremarine/sbg-ecom') + +const isString = value => typeof value === 'string' || value instanceof String +const isBoolean = value => typeof value === 'boolean' || value instanceof Boolean +const isNullOrUndefined = value => value === null || value === undefined +const isBuffer = value => Buffer.isBuffer(value) + +const setParser = (parser, { memory, firmware }) => { + if (isBoolean(memory)) { + parser.memory = memory + } + if (isString(firmware)) { + try { + parser.firmware = firmware + } catch (error) { + console.error(`SBG Error: Invalid firmware ${firmware}`) + console.error(error) + } + } +} + +const getMemory = (parser, memory) => { + // Not memory + if (isNullOrUndefined(memory)) { return undefined } + const { command, payload } = memory + // Memory command + if (!isNullOrUndefined(command)) { + if (isString(command)) { + // Memory set + if (command === 'set') { + if (!isBoolean(payload)) { + return 'memory.payload should be boolean' + } + parser.memory = payload + return { + memory: parser.memory, + characters: parser.bufferLimit + } + } + // Memory get + if (command === 'get') { + return { + memory: parser.memory, + characters: parser.bufferLimit + } + } + } + return 'memory.command should be "get" or "set"' + } + // Invalid value + return 'invalid memory input' +} + +const getFirmware = (parser, firmware) => { + // Not firmware + if (isNullOrUndefined(firmware)) { return undefined } + const { command, payload } = firmware + // Firmware command + if (!isNullOrUndefined(command)) { + if (isString(command)) { + // Firmware set + if (command === 'set') { + if (!isString(payload)) { + return 'firmware.payload should be a string number' + } + try { + parser.firmware = payload + return { firmware: parser.firmware } + } catch (error) { + console.error(`invalid firmware -> ${firmware}`) + } + } + // Firmware get + if (command === 'get') { + return { firmware: parser.firmware } + } + } + return 'firmware.command should be "get" or "set"' + } + // Invalid value + return 'invalid firmware input' +} + +const getFirmwares = (parser, firmwares) => { + // Not sentence + if (isNullOrUndefined(firmwares)) { return undefined } + // Sentence + return parser.getAvailableFirmwares() +} + +const getPayload = (parser, payload) => { + // Not payload + if (isNullOrUndefined(payload)) { return undefined } + // Payload + if (isBuffer(payload)) { + parser.addData(payload) + return parser.getFrames() + } + // Invalid payload + return 'payload must be a Buffer' +} + +const cleanUndefineds = (msg) => { + Object.keys(msg).forEach(key => { + if (msg[key] === undefined) { + delete msg[key] + } + }) +} + +module.exports = function (RED) { + // Component + function SBGECom (config) { + RED.nodes.createNode(this, config) + const node = this + Object.assign(node, config) + // Logic + let parser = null + try { + parser = new Parser() + setParser(parser, config) + } catch (err) { + node.error(err, 'problem setting up NMEA parser') + } + // Input + node.on('input', (msg, send, done) => { + let error = null + try { + const { memory, firmwares, firmware, payload } = msg + // Memory + msg.memory = getMemory(parser, memory) + if (msg.memory === undefined) { delete msg.memory } + // Firmwares + msg.firmwares = getFirmwares(parser, firmwares) + // Firmware + msg.firmware = getFirmware(parser, firmware) + // Payload + msg.payload = getPayload(parser, payload) + // Clean undefined props + cleanUndefineds(msg) + // Send msg + send(msg) + } catch (err) { + error = err + } finally { + // Finish + if (done) { (error === null) ? done() : done(error) } + } + }) + } + // Register + RED.nodes.registerType('cma-sbg-ecom', SBGECom) +} diff --git a/packages/sbg-ecom-nodered/tests/nodered/components/package.json b/packages/sbg-ecom-nodered/tests/nodered/components/package.json new file mode 100755 index 0000000..0c369aa --- /dev/null +++ b/packages/sbg-ecom-nodered/tests/nodered/components/package.json @@ -0,0 +1,49 @@ +{ + "name": "@coremarine/sbg-ecom-nodered", + "private": true, + "version": "0.0.1", + "author": "CoreMarine", + "license": "MIT", + "description": "sbg-ecom", + "homepage": "https://github.com/core-marine-dev/devices/tree/main/packages/sbg-ecom-nodered", + "repository": { + "type": "git", + "url": "git+https://github.com/core-marine-dev/devices.git" + }, + "bugs": { + "url": "https://github.com/core-marine-dev/devices/issues" + }, + "keywords": [ + "sbg-ecom", + "sbg", + "gnss", + "gps", + "mru", + "imu", + "binary", + "protocol", + "parser" + ], + "engines": { + "node": ">=18.0.0" + }, + "node-red": { + "version": ">=3.0.0", + "nodes": { + "cma-sbg-ecom": "src/parser.js" + } + }, + "main": "index.js", + "files": [ + "src", + "examples" + ], + "scripts": { + "docker": "sh manual_tests.sh", + "test": "mocha \"tests/**/*.test.js\"", + "test:vitest": "vitest" + }, + "dependencies": { + "@coremarine/sbg-ecom": ">=0.0.1" + } +} diff --git a/packages/sbg-ecom-nodered/tests/nodered/components/src/icons/cma-logo-blue.png b/packages/sbg-ecom-nodered/tests/nodered/components/src/icons/cma-logo-blue.png new file mode 100755 index 0000000000000000000000000000000000000000..c33c2d871d8580a09d4c7baf38afbf6fffef006c GIT binary patch literal 15621 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 AjQ{`u literal 0 HcmV?d00001 diff --git a/packages/sbg-ecom-nodered/tests/nodered/components/src/icons/cma-logo-white.png b/packages/sbg-ecom-nodered/tests/nodered/components/src/icons/cma-logo-white.png new file mode 100755 index 0000000000000000000000000000000000000000..8fc7b25bdb2ee4a8249280696b235b8974129b35 GIT binary patch literal 15531 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 + + + + + + + diff --git a/packages/sbg-ecom-nodered/tests/nodered/components/src/parser.js b/packages/sbg-ecom-nodered/tests/nodered/components/src/parser.js new file mode 100755 index 0000000..c3607ce --- /dev/null +++ b/packages/sbg-ecom-nodered/tests/nodered/components/src/parser.js @@ -0,0 +1,153 @@ +const { SBGParser: Parser } = require('@coremarine/sbg-ecom') + +const isString = value => typeof value === 'string' || value instanceof String +const isBoolean = value => typeof value === 'boolean' || value instanceof Boolean +const isNullOrUndefined = value => value === null || value === undefined +const isBuffer = value => Buffer.isBuffer(value) + +const setParser = (parser, { memory, firmware }) => { + if (isBoolean(memory)) { + parser.memory = memory + } + if (isString(firmware)) { + try { + parser.firmware = firmware + } catch (error) { + console.error(`SBG Error: Invalid firmware ${firmware}`) + console.error(error) + } + } +} + +const getMemory = (parser, memory) => { + // Not memory + if (isNullOrUndefined(memory)) { return undefined } + const { command, payload } = memory + // Memory command + if (!isNullOrUndefined(command)) { + if (isString(command)) { + // Memory set + if (command === 'set') { + if (!isBoolean(payload)) { + return 'memory.payload should be boolean' + } + parser.memory = payload + return { + memory: parser.memory, + characters: parser.bufferLimit + } + } + // Memory get + if (command === 'get') { + return { + memory: parser.memory, + characters: parser.bufferLimit + } + } + } + return 'memory.command should be "get" or "set"' + } + // Invalid value + return 'invalid memory input' +} + +const getFirmware = (parser, firmware) => { + // Not firmware + if (isNullOrUndefined(firmware)) { return undefined } + const { command, payload } = firmware + // Firmware command + if (!isNullOrUndefined(command)) { + if (isString(command)) { + // Firmware set + if (command === 'set') { + if (!isString(payload)) { + return 'firmware.payload should be a string number' + } + try { + parser.firmware = payload + return { firmware: parser.firmware } + } catch (error) { + console.error(`invalid firmware -> ${firmware}`) + } + } + // Firmware get + if (command === 'get') { + return { firmware: parser.firmware } + } + } + return 'firmware.command should be "get" or "set"' + } + // Invalid value + return 'invalid firmware input' +} + +const getFirmwares = (parser, firmwares) => { + // Not sentence + if (isNullOrUndefined(firmwares)) { return undefined } + // Sentence + return parser.getAvailableFirmwares() +} + +const getPayload = (parser, payload) => { + // Not payload + if (isNullOrUndefined(payload)) { return undefined } + // Payload + if (isBuffer(payload)) { + parser.addData(payload) + return parser.getFrames() + } + // Invalid payload + return 'payload must be a Buffer' +} + +const cleanUndefineds = (msg) => { + Object.keys(msg).forEach(key => { + if (msg[key] === undefined) { + delete msg[key] + } + }) +} + +module.exports = function (RED) { + // Component + function SBGECom (config) { + RED.nodes.createNode(this, config) + const node = this + Object.assign(node, config) + // Logic + let parser = null + try { + parser = new Parser() + setParser(parser, config) + } catch (err) { + node.error(err, 'problem setting up NMEA parser') + } + // Input + node.on('input', (msg, send, done) => { + let error = null + try { + const { memory, firmwares, firmware, payload } = msg + // Memory + msg.memory = getMemory(parser, memory) + if (msg.memory === undefined) { delete msg.memory } + // Firmwares + msg.firmwares = getFirmwares(parser, firmwares) + // Firmware + msg.firmware = getFirmware(parser, firmware) + // Payload + msg.payload = getPayload(parser, payload) + // Clean undefined props + cleanUndefineds(msg) + // Send msg + send(msg) + } catch (err) { + error = err + } finally { + // Finish + if (done) { (error === null) ? done() : done(error) } + } + }) + } + // Register + RED.nodes.registerType('cma-sbg-ecom', SBGECom) +} diff --git a/packages/sbg-ecom-nodered/tests/nodered/data/flows.json b/packages/sbg-ecom-nodered/tests/nodered/data/flows.json new file mode 100644 index 0000000..4ffac12 --- /dev/null +++ b/packages/sbg-ecom-nodered/tests/nodered/data/flows.json @@ -0,0 +1,379 @@ +[ + { + "id": "86f1271d07a48b44", + "type": "tab", + "label": "SBGEcom Parser Examples", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "9283b11f486aa6af", + "type": "group", + "z": "86f1271d07a48b44", + "name": "Flow Errors", + "style": { + "stroke": "#000000", + "label": true, + "color": "#000000" + }, + "nodes": [ + "3dcdbb2ff53d1ac2", + "cd7a546b03381262" + ], + "x": 34, + "y": 19, + "w": 352, + "h": 82 + }, + { + "id": "fa79e06be881de74", + "type": "group", + "z": "86f1271d07a48b44", + "name": "Examples", + "style": { + "stroke": "#000000", + "label": true, + "color": "#000000" + }, + "nodes": [ + "bf1bf2211a0a99f4", + "0d643452dedfda51", + "bab379433f7607f5", + "2a2312ddbf6c1d4c", + "1b7de497daf8146e", + "b2dd2fc884f2b756", + "0866325a71bf54c8", + "50ec56828023ecac", + "cf83530668c8884e", + "95faf8f169dbc837", + "1a18d2d87afbf6c9", + "eb57049a15b736b8", + "8c98d96f36590d9d" + ], + "x": 34, + "y": 139, + "w": 672, + "h": 382 + }, + { + "id": "3dcdbb2ff53d1ac2", + "type": "catch", + "z": "86f1271d07a48b44", + "g": "9283b11f486aa6af", + "name": "ERRORS", + "scope": null, + "uncaught": false, + "x": 120, + "y": 60, + "wires": [ + [ + "cd7a546b03381262" + ] + ] + }, + { + "id": "cd7a546b03381262", + "type": "debug", + "z": "86f1271d07a48b44", + "g": "9283b11f486aa6af", + "name": "ERRORS", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 280, + "y": 60, + "wires": [] + }, + { + "id": "bf1bf2211a0a99f4", + "type": "debug", + "z": "86f1271d07a48b44", + "g": "fa79e06be881de74", + "name": "Payload", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "payload", + "targetType": "msg", + "statusVal": "", + "statusType": "auto", + "x": 580, + "y": 260, + "wires": [] + }, + { + "id": "0d643452dedfda51", + "type": "inject", + "z": "86f1271d07a48b44", + "g": "fa79e06be881de74", + "name": "Memory ON", + "props": [ + { + "p": "memory", + "v": "{\"command\":\"set\",\"payload\":true}", + "vt": "json" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 150, + "y": 280, + "wires": [ + [ + "2a2312ddbf6c1d4c" + ] + ] + }, + { + "id": "bab379433f7607f5", + "type": "inject", + "z": "86f1271d07a48b44", + "g": "fa79e06be881de74", + "name": "Memory OFF", + "props": [ + { + "p": "memory", + "v": "{\"command\":\"set\",\"payload\":false}", + "vt": "json" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 150, + "y": 240, + "wires": [ + [ + "2a2312ddbf6c1d4c" + ] + ] + }, + { + "id": "2a2312ddbf6c1d4c", + "type": "cma-sbg-ecom", + "z": "86f1271d07a48b44", + "g": "fa79e06be881de74", + "name": "", + "memory": true, + "firmware": "2.3", + "x": 420, + "y": 340, + "wires": [ + [ + "bf1bf2211a0a99f4", + "8c98d96f36590d9d" + ] + ] + }, + { + "id": "1b7de497daf8146e", + "type": "inject", + "z": "86f1271d07a48b44", + "g": "fa79e06be881de74", + "name": "Send data", + "props": [], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 140, + "y": 180, + "wires": [ + [ + "b2dd2fc884f2b756" + ] + ] + }, + { + "id": "b2dd2fc884f2b756", + "type": "file in", + "z": "86f1271d07a48b44", + "g": "fa79e06be881de74", + "name": "", + "filename": "/tests/sbg-raw.bin", + "filenameType": "str", + "format": "", + "chunk": false, + "sendError": false, + "encoding": "none", + "allProps": false, + "x": 330, + "y": 180, + "wires": [ + [ + "2a2312ddbf6c1d4c" + ] + ] + }, + { + "id": "0866325a71bf54c8", + "type": "inject", + "z": "86f1271d07a48b44", + "g": "fa79e06be881de74", + "name": "Get All Available Firmwares", + "props": [ + { + "p": "firmwares", + "v": "{}", + "vt": "json" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 190, + "y": 340, + "wires": [ + [ + "2a2312ddbf6c1d4c" + ] + ] + }, + { + "id": "50ec56828023ecac", + "type": "inject", + "z": "86f1271d07a48b44", + "g": "fa79e06be881de74", + "name": "Set Firmware 2.3", + "props": [ + { + "p": "firmware", + "v": "{\"command\":\"set\",\"payload\":\"2.3\"}", + "vt": "json" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 160, + "y": 440, + "wires": [ + [ + "2a2312ddbf6c1d4c" + ] + ] + }, + { + "id": "cf83530668c8884e", + "type": "inject", + "z": "86f1271d07a48b44", + "g": "fa79e06be881de74", + "name": "Set Firmware 3.2", + "props": [ + { + "p": "firmware", + "v": "{\"command\":\"set\",\"payload\":\"2.3\"}", + "vt": "json" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 160, + "y": 480, + "wires": [ + [ + "2a2312ddbf6c1d4c" + ] + ] + }, + { + "id": "95faf8f169dbc837", + "type": "inject", + "z": "86f1271d07a48b44", + "g": "fa79e06be881de74", + "name": "Get Firmware", + "props": [ + { + "p": "firmware", + "v": "{\"command\":\"get\"}", + "vt": "json" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 150, + "y": 400, + "wires": [ + [ + "2a2312ddbf6c1d4c" + ] + ] + }, + { + "id": "1a18d2d87afbf6c9", + "type": "debug", + "z": "86f1271d07a48b44", + "g": "fa79e06be881de74", + "name": "Memory", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "memory", + "targetType": "msg", + "statusVal": "", + "statusType": "auto", + "x": 580, + "y": 300, + "wires": [] + }, + { + "id": "eb57049a15b736b8", + "type": "debug", + "z": "86f1271d07a48b44", + "g": "fa79e06be881de74", + "name": "Firmwares", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "firmwares", + "targetType": "msg", + "statusVal": "", + "statusType": "auto", + "x": 590, + "y": 340, + "wires": [] + }, + { + "id": "8c98d96f36590d9d", + "type": "debug", + "z": "86f1271d07a48b44", + "g": "fa79e06be881de74", + "name": "Firmware", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "firmware", + "targetType": "msg", + "statusVal": "", + "statusType": "auto", + "x": 580, + "y": 380, + "wires": [] + } +] \ No newline at end of file diff --git a/packages/sbg-ecom-nodered/tests/nodered/data/settings.js b/packages/sbg-ecom-nodered/tests/nodered/data/settings.js new file mode 100755 index 0000000..ea50f4a --- /dev/null +++ b/packages/sbg-ecom-nodered/tests/nodered/data/settings.js @@ -0,0 +1,542 @@ +/** + * This is the default settings file provided by Node-RED. + * + * It can contain any valid JavaScript code that will get run when Node-RED + * is started. + * + * Lines that start with // are commented out. + * Each entry should be separated from the entries above and below by a comma ',' + * + * For more information about individual settings, refer to the documentation: + * https://nodered.org/docs/user-guide/runtime/configuration + * + * The settings are split into the following sections: + * - Flow File and User Directory Settings + * - Security + * - Server Settings + * - Runtime Settings + * - Editor Settings + * - Node Settings + * + **/ + +module.exports = { + +/******************************************************************************* + * Flow File and User Directory Settings + * - flowFile + * - credentialSecret + * - flowFilePretty + * - userDir + * - nodesDir + ******************************************************************************/ + + /** The file containing the flows. If not set, defaults to flows_.json **/ + flowFile: 'flows.json', + + /** By default, credentials are encrypted in storage using a generated key. To + * specify your own secret, set the following property. + * If you want to disable encryption of credentials, set this property to false. + * Note: once you set this property, do not change it - doing so will prevent + * node-red from being able to decrypt your existing credentials and they will be + * lost. + */ + //credentialSecret: "a-secret-key", + + /** By default, the flow JSON will be formatted over multiple lines making + * it easier to compare changes when using version control. + * To disable pretty-printing of the JSON set the following property to false. + */ + flowFilePretty: true, + + /** By default, all user data is stored in a directory called `.node-red` under + * the user's home directory. To use a different location, the following + * property can be used + */ + //userDir: '/home/nol/.node-red/', + + /** Node-RED scans the `nodes` directory in the userDir to find local node files. + * The following property can be used to specify an additional directory to scan. + */ + //nodesDir: '/home/nol/.node-red/nodes', + +/******************************************************************************* + * Security + * - adminAuth + * - https + * - httpsRefreshInterval + * - requireHttps + * - httpNodeAuth + * - httpStaticAuth + ******************************************************************************/ + + /** To password protect the Node-RED editor and admin API, the following + * property can be used. See http://nodered.org/docs/security.html for details. + */ + //adminAuth: { + // type: "credentials", + // users: [{ + // username: "admin", + // password: "$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN.", + // permissions: "*" + // }] + //}, + + /** The following property can be used to enable HTTPS + * This property can be either an object, containing both a (private) key + * and a (public) certificate, or a function that returns such an object. + * See http://nodejs.org/api/https.html#https_https_createserver_options_requestlistener + * for details of its contents. + */ + + /** Option 1: static object */ + //https: { + // key: require("fs").readFileSync('privkey.pem'), + // cert: require("fs").readFileSync('cert.pem') + //}, + + /** Option 2: function that returns the HTTP configuration object */ + // https: function() { + // // This function should return the options object, or a Promise + // // that resolves to the options object + // return { + // key: require("fs").readFileSync('privkey.pem'), + // cert: require("fs").readFileSync('cert.pem') + // } + // }, + + /** If the `https` setting is a function, the following setting can be used + * to set how often, in hours, the function will be called. That can be used + * to refresh any certificates. + */ + //httpsRefreshInterval : 12, + + /** The following property can be used to cause insecure HTTP connections to + * be redirected to HTTPS. + */ + //requireHttps: true, + + /** To password protect the node-defined HTTP endpoints (httpNodeRoot), + * including node-red-dashboard, or the static content (httpStatic), the + * following properties can be used. + * The `pass` field is a bcrypt hash of the password. + * See http://nodered.org/docs/security.html#generating-the-password-hash + */ + //httpNodeAuth: {user:"user",pass:"$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN."}, + //httpStaticAuth: {user:"user",pass:"$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN."}, + +/******************************************************************************* + * Server Settings + * - uiPort + * - uiHost + * - apiMaxLength + * - httpServerOptions + * - httpAdminRoot + * - httpAdminMiddleware + * - httpNodeRoot + * - httpNodeCors + * - httpNodeMiddleware + * - httpStatic + * - httpStaticRoot + ******************************************************************************/ + + /** the tcp port that the Node-RED web server is listening on */ + uiPort: process.env.PORT || 1880, + + /** By default, the Node-RED UI accepts connections on all IPv4 interfaces. + * To listen on all IPv6 addresses, set uiHost to "::", + * The following property can be used to listen on a specific interface. For + * example, the following would only allow connections from the local machine. + */ + //uiHost: "127.0.0.1", + + /** The maximum size of HTTP request that will be accepted by the runtime api. + * Default: 5mb + */ + //apiMaxLength: '5mb', + + /** The following property can be used to pass custom options to the Express.js + * server used by Node-RED. For a full list of available options, refer + * to http://expressjs.com/en/api.html#app.settings.table + */ + //httpServerOptions: { }, + + /** By default, the Node-RED UI is available at http://localhost:1880/ + * The following property can be used to specify a different root path. + * If set to false, this is disabled. + */ + //httpAdminRoot: '/admin', + + /** The following property can be used to add a custom middleware function + * in front of all admin http routes. For example, to set custom http + * headers. It can be a single function or an array of middleware functions. + */ + // httpAdminMiddleware: function(req,res,next) { + // // Set the X-Frame-Options header to limit where the editor + // // can be embedded + // //res.set('X-Frame-Options', 'sameorigin'); + // next(); + // }, + + + /** Some nodes, such as HTTP In, can be used to listen for incoming http requests. + * By default, these are served relative to '/'. The following property + * can be used to specifiy a different root path. If set to false, this is + * disabled. + */ + //httpNodeRoot: '/red-nodes', + + /** The following property can be used to configure cross-origin resource sharing + * in the HTTP nodes. + * See https://github.com/troygoode/node-cors#configuration-options for + * details on its contents. The following is a basic permissive set of options: + */ + //httpNodeCors: { + // origin: "*", + // methods: "GET,PUT,POST,DELETE" + //}, + + /** If you need to set an http proxy please set an environment variable + * called http_proxy (or HTTP_PROXY) outside of Node-RED in the operating system. + * For example - http_proxy=http://myproxy.com:8080 + * (Setting it here will have no effect) + * You may also specify no_proxy (or NO_PROXY) to supply a comma separated + * list of domains to not proxy, eg - no_proxy=.acme.co,.acme.co.uk + */ + + /** The following property can be used to add a custom middleware function + * in front of all http in nodes. This allows custom authentication to be + * applied to all http in nodes, or any other sort of common request processing. + * It can be a single function or an array of middleware functions. + */ + //httpNodeMiddleware: function(req,res,next) { + // // Handle/reject the request, or pass it on to the http in node by calling next(); + // // Optionally skip our rawBodyParser by setting this to true; + // //req.skipRawBodyParser = true; + // next(); + //}, + + /** When httpAdminRoot is used to move the UI to a different root path, the + * following property can be used to identify a directory of static content + * that should be served at http://localhost:1880/. + * When httpStaticRoot is set differently to httpAdminRoot, there is no need + * to move httpAdminRoot + */ + //httpStatic: '/home/nol/node-red-static/', //single static source + /* OR multiple static sources can be created using an array of objects... */ + //httpStatic: [ + // {path: '/home/nol/pics/', root: "/img/"}, + // {path: '/home/nol/reports/', root: "/doc/"}, + //], + + /** + * All static routes will be appended to httpStaticRoot + * e.g. if httpStatic = "/home/nol/docs" and httpStaticRoot = "/static/" + * then "/home/nol/docs" will be served at "/static/" + * e.g. if httpStatic = [{path: '/home/nol/pics/', root: "/img/"}] + * and httpStaticRoot = "/static/" + * then "/home/nol/pics/" will be served at "/static/img/" + */ + //httpStaticRoot: '/static/', + +/******************************************************************************* + * Runtime Settings + * - lang + * - runtimeState + * - diagnostics + * - logging + * - contextStorage + * - exportGlobalContextKeys + * - externalModules + ******************************************************************************/ + + /** Uncomment the following to run node-red in your preferred language. + * Available languages include: en-US (default), ja, de, zh-CN, zh-TW, ru, ko + * Some languages are more complete than others. + */ + // lang: "de", + + /** Configure diagnostics options + * - enabled: When `enabled` is `true` (or unset), diagnostics data will + * be available at http://localhost:1880/diagnostics + * - ui: When `ui` is `true` (or unset), the action `show-system-info` will + * be available to logged in users of node-red editor + */ + diagnostics: { + /** enable or disable diagnostics endpoint. Must be set to `false` to disable */ + enabled: true, + /** enable or disable diagnostics display in the node-red editor. Must be set to `false` to disable */ + ui: true, + }, + /** Configure runtimeState options + * - enabled: When `enabled` is `true` flows runtime can be Started/Stoped + * by POSTing to available at http://localhost:1880/flows/state + * - ui: When `ui` is `true`, the action `core:start-flows` and + * `core:stop-flows` will be available to logged in users of node-red editor + * Also, the deploy menu (when set to default) will show a stop or start button + */ + runtimeState: { + /** enable or disable flows/state endpoint. Must be set to `false` to disable */ + enabled: false, + /** show or hide runtime stop/start options in the node-red editor. Must be set to `false` to hide */ + ui: false, + }, + /** Configure the logging output */ + logging: { + /** Only console logging is currently supported */ + console: { + /** Level of logging to be recorded. Options are: + * fatal - only those errors which make the application unusable should be recorded + * error - record errors which are deemed fatal for a particular request + fatal errors + * warn - record problems which are non fatal + errors + fatal errors + * info - record information about the general running of the application + warn + error + fatal errors + * debug - record information which is more verbose than info + info + warn + error + fatal errors + * trace - record very detailed logging + debug + info + warn + error + fatal errors + * off - turn off all logging (doesn't affect metrics or audit) + */ + level: "info", + /** Whether or not to include metric events in the log output */ + metrics: false, + /** Whether or not to include audit events in the log output */ + audit: false + } + }, + + /** Context Storage + * The following property can be used to enable context storage. The configuration + * provided here will enable file-based context that flushes to disk every 30 seconds. + * Refer to the documentation for further options: https://nodered.org/docs/api/context/ + */ + //contextStorage: { + // default: { + // module:"localfilesystem" + // }, + //}, + + /** `global.keys()` returns a list of all properties set in global context. + * This allows them to be displayed in the Context Sidebar within the editor. + * In some circumstances it is not desirable to expose them to the editor. The + * following property can be used to hide any property set in `functionGlobalContext` + * from being list by `global.keys()`. + * By default, the property is set to false to avoid accidental exposure of + * their values. Setting this to true will cause the keys to be listed. + */ + exportGlobalContextKeys: false, + + /** Configure how the runtime will handle external npm modules. + * This covers: + * - whether the editor will allow new node modules to be installed + * - whether nodes, such as the Function node are allowed to have their + * own dynamically configured dependencies. + * The allow/denyList options can be used to limit what modules the runtime + * will install/load. It can use '*' as a wildcard that matches anything. + */ + externalModules: { + // autoInstall: false, /** Whether the runtime will attempt to automatically install missing modules */ + // autoInstallRetry: 30, /** Interval, in seconds, between reinstall attempts */ + // palette: { /** Configuration for the Palette Manager */ + // allowInstall: true, /** Enable the Palette Manager in the editor */ + // allowUpdate: true, /** Allow modules to be updated in the Palette Manager */ + // allowUpload: true, /** Allow module tgz files to be uploaded and installed */ + // allowList: ['*'], + // denyList: [], + // allowUpdateList: ['*'], + // denyUpdateList: [] + // }, + // modules: { /** Configuration for node-specified modules */ + // allowInstall: true, + // allowList: [], + // denyList: [] + // } + }, + + +/******************************************************************************* + * Editor Settings + * - disableEditor + * - editorTheme + ******************************************************************************/ + + /** The following property can be used to disable the editor. The admin API + * is not affected by this option. To disable both the editor and the admin + * API, use either the httpRoot or httpAdminRoot properties + */ + //disableEditor: false, + + /** Customising the editor + * See https://nodered.org/docs/user-guide/runtime/configuration#editor-themes + * for all available options. + */ + editorTheme: { + /** The following property can be used to set a custom theme for the editor. + * See https://github.com/node-red-contrib-themes/theme-collection for + * a collection of themes to chose from. + */ + //theme: "", + + /** To disable the 'Welcome to Node-RED' tour that is displayed the first + * time you access the editor for each release of Node-RED, set this to false + */ + //tours: false, + + palette: { + /** The following property can be used to order the categories in the editor + * palette. If a node's category is not in the list, the category will get + * added to the end of the palette. + * If not set, the following default order is used: + */ + categories: ['CoreMarine', 'subflows', 'common', 'function', 'network', 'sequence', 'parser', 'storage'], + }, + + projects: { + /** To enable the Projects feature, set this value to true */ + enabled: false, + workflow: { + /** Set the default projects workflow mode. + * - manual - you must manually commit changes + * - auto - changes are automatically committed + * This can be overridden per-user from the 'Git config' + * section of 'User Settings' within the editor + */ + mode: "manual" + } + }, + + codeEditor: { + /** Select the text editor component used by the editor. + * As of Node-RED V3, this defaults to "monaco", but can be set to "ace" if desired + */ + lib: "monaco", + options: { + /** The follow options only apply if the editor is set to "monaco" + * + * theme - must match the file name of a theme in + * packages/node_modules/@node-red/editor-client/src/vendor/monaco/dist/theme + * e.g. "tomorrow-night", "upstream-sunburst", "github", "my-theme" + */ + // theme: "vs", + /** other overrides can be set e.g. fontSize, fontFamily, fontLigatures etc. + * for the full list, see https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.IStandaloneEditorConstructionOptions.html + */ + //fontSize: 14, + //fontFamily: "Cascadia Code, Fira Code, Consolas, 'Courier New', monospace", + //fontLigatures: true, + } + } + }, + +/******************************************************************************* + * Node Settings + * - fileWorkingDirectory + * - functionGlobalContext + * - functionExternalModules + * - nodeMessageBufferMaxLength + * - ui (for use with Node-RED Dashboard) + * - debugUseColors + * - debugMaxLength + * - execMaxBufferSize + * - httpRequestTimeout + * - mqttReconnectTime + * - serialReconnectTime + * - socketReconnectTime + * - socketTimeout + * - tcpMsgQueueSize + * - inboundWebSocketTimeout + * - tlsConfigDisableLocalFiles + * - webSocketNodeVerifyClient + ******************************************************************************/ + + /** The working directory to handle relative file paths from within the File nodes + * defaults to the working directory of the Node-RED process. + */ + //fileWorkingDirectory: "", + + /** Allow the Function node to load additional npm modules directly */ + functionExternalModules: true, + + /** The following property can be used to set predefined values in Global Context. + * This allows extra node modules to be made available with in Function node. + * For example, the following: + * functionGlobalContext: { os:require('os') } + * will allow the `os` module to be accessed in a Function node using: + * global.get("os") + */ + functionGlobalContext: { + // os:require('os'), + }, + + /** The maximum number of messages nodes will buffer internally as part of their + * operation. This applies across a range of nodes that operate on message sequences. + * defaults to no limit. A value of 0 also means no limit is applied. + */ + //nodeMessageBufferMaxLength: 0, + + /** If you installed the optional node-red-dashboard you can set it's path + * relative to httpNodeRoot + * Other optional properties include + * readOnly:{boolean}, + * middleware:{function or array}, (req,res,next) - http middleware + * ioMiddleware:{function or array}, (socket,next) - socket.io middleware + */ + //ui: { path: "ui" }, + + /** Colourise the console output of the debug node */ + //debugUseColors: true, + + /** The maximum length, in characters, of any message sent to the debug sidebar tab */ + debugMaxLength: 1000, + + /** Maximum buffer size for the exec node. Defaults to 10Mb */ + //execMaxBufferSize: 10000000, + + /** Timeout in milliseconds for HTTP request connections. Defaults to 120s */ + //httpRequestTimeout: 120000, + + /** Retry time in milliseconds for MQTT connections */ + mqttReconnectTime: 15000, + + /** Retry time in milliseconds for Serial port connections */ + serialReconnectTime: 15000, + + /** Retry time in milliseconds for TCP socket connections */ + //socketReconnectTime: 10000, + + /** Timeout in milliseconds for TCP server socket connections. Defaults to no timeout */ + //socketTimeout: 120000, + + /** Maximum number of messages to wait in queue while attempting to connect to TCP socket + * defaults to 1000 + */ + //tcpMsgQueueSize: 2000, + + /** Timeout in milliseconds for inbound WebSocket connections that do not + * match any configured node. Defaults to 5000 + */ + //inboundWebSocketTimeout: 5000, + + /** To disable the option for using local files for storing keys and + * certificates in the TLS configuration node, set this to true. + */ + //tlsConfigDisableLocalFiles: true, + + /** The following property can be used to verify websocket connection attempts. + * This allows, for example, the HTTP request headers to be checked to ensure + * they include valid authentication information. + */ + //webSocketNodeVerifyClient: function(info) { + // /** 'info' has three properties: + // * - origin : the value in the Origin header + // * - req : the HTTP request + // * - secure : true if req.connection.authorized or req.connection.encrypted is set + // * + // * The function should return true if the connection should be accepted, false otherwise. + // * + // * Alternatively, if this function is defined to accept a second argument, callback, + // * it can be used to verify the client asynchronously. + // * The callback takes three arguments: + // * - result : boolean, whether to accept the connection or not + // * - code : if result is false, the HTTP error status to return + // * - reason: if result is false, the HTTP reason string to return + // */ + //}, +} diff --git a/packages/sbg-ecom-nodered/tests/nodered/tests/sbg-raw.bin b/packages/sbg-ecom-nodered/tests/nodered/tests/sbg-raw.bin new file mode 100644 index 0000000000000000000000000000000000000000..828bd11fa6094cdcf23d4e428531ec82c15a1f3c GIT binary patch literal 11776 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 literal 0 HcmV?d00001 diff --git a/packages/sbg-ecom-nodered/vitest.config.ts b/packages/sbg-ecom-nodered/vitest.config.ts new file mode 100755 index 0000000..658631d --- /dev/null +++ b/packages/sbg-ecom-nodered/vitest.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + test: { + // ... Specify options here. + coverage: { + exclude: [ + '**/*/constants.ts', + '**/*/types.ts' + ] + } + } +})