From 6ffb6dd6a3e76628f7238e67d7058b5dcea32574 Mon Sep 17 00:00:00 2001 From: Ethan Li Date: Wed, 28 Feb 2024 08:46:27 -0800 Subject: [PATCH] Initialize files from the main pscopehat node-red-dashboard --- .github/workflows/build.yml | 136 + Dockerfile | 11 + flows.json | 10965 ++++++++++++++++++++++++++++++++++ package-lock.json | 1113 ++++ package.json | 21 + 5 files changed, 12246 insertions(+) create mode 100644 .github/workflows/build.yml create mode 100644 Dockerfile create mode 100644 flows.json create mode 100644 package-lock.json create mode 100644 package.json diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..1fae5b8 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,136 @@ +name: Build Docker container image for the Node-RED dashboard + +on: + push: + branches: + - 'main' + - 'beta' + - 'stable' + pull_request: + merge_group: + workflow_dispatch: + inputs: + git-ref: + description: 'Git ref (optional)' + required: false + +env: + REGISTRY_IMAGE: ghcr.io/planktoscope/segmenter-node-red-dashboard + +jobs: + build: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + platform: + - linux/amd64 + - linux/arm64 + - linux/arm/v7 + permissions: + contents: read + packages: write + steps: + - uses: actions/checkout@v4 + + - name: Prepare environment variables + run: | + platform=${{ matrix.platform }} + echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV + + # Build and publish Docker container image + - name: Get Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY_IMAGE }} + tags: | + type=sha + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push by digest + id: build + uses: docker/build-push-action@v5 + with: + pull: true + push: ${{ github.event_name == 'pull_request' || github.event_name == 'push' || github.event_name == 'push tag' }} + platforms: ${{ matrix.platform }} + tags: ${{ env.REGISTRY_IMAGE }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha,scope=build-${{ matrix.platform }} + cache-to: type=gha,mode=max,scope=build-${{ matrix.platform }} + outputs: type=image,name=${{ env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true + + - name: Export digest + run: | + mkdir -p /tmp/digests + digest="${{ steps.build.outputs.digest }}" + touch "/tmp/digests/${digest#sha256:}" + + - name: Upload digest + uses: actions/upload-artifact@v4 + with: + name: digests-${{ env.PLATFORM_PAIR }} + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 + + merge: + runs-on: ubuntu-latest + needs: + - build + steps: + - name: Download digests + uses: actions/download-artifact@v4 + with: + path: /tmp/digests + pattern: digests-* + merge-multiple: true + + # Build and publish Docker container image + - name: Get Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY_IMAGE }} + tags: | + type=match,pattern=v(.*),group=1 + type=edge,branch=main + type=ref,event=branch,enable=${{ github.ref != format('refs/heads/{0}', 'main') && github.ref != format('refs/heads/{0}', 'main') }} + type=ref,event=pr + type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'stable') }} + type=sha + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + if: github.event_name == 'pull_request' || github.event_name == 'push' || github.event_name == 'push tag' + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Create manifest list and push + working-directory: /tmp/digests + if: github.event_name == 'pull_request' || github.event_name == 'push' || github.event_name == 'push tag' + run: | + docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *) + + - name: Inspect image + run: | + docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.meta.outputs.version }} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..0a27408 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +FROM nodered/node-red:3.1.5-18-minimal + +WORKDIR /data +COPY package.json /data +COPY package-lock.json /data +RUN npm install --unsave-perm --no-update-notifier --no-fund --only=production +WORKDIR /usr/src/node-red + +COPY settings.js /data/settings.js +COPY flows.json /data/flows.json + diff --git a/flows.json b/flows.json new file mode 100644 index 0000000..d1fddf3 --- /dev/null +++ b/flows.json @@ -0,0 +1,10965 @@ +[ + { + "id": "eaae323a.31b3", + "type": "tab", + "label": "Home", + "disabled": false, + "info": "" + }, + { + "id": "b771c342.49603", + "type": "tab", + "label": "Sample", + "disabled": false, + "info": "" + }, + { + "id": "bccd1f23.87219", + "type": "tab", + "label": "Optic Configuration", + "disabled": false, + "info": "" + }, + { + "id": "baa1e3d9.cb29d", + "type": "tab", + "label": "Fluidic Acquisition", + "disabled": false, + "info": "" + }, + { + "id": "cb95299c.2817c8", + "type": "tab", + "label": "Segmentation", + "disabled": false, + "info": "" + }, + { + "id": "c1660bc.e7ff7f8", + "type": "tab", + "label": "Gallery", + "disabled": false, + "info": "" + }, + { + "id": "9daf9e2b.019fc", + "type": "tab", + "label": "Administration", + "disabled": false, + "info": "" + }, + { + "id": "1371dec5.76e671", + "type": "tab", + "label": "System Monitoring", + "disabled": false, + "info": "" + }, + { + "id": "f21ba04.c26266", + "type": "tab", + "label": "WIFI Management", + "disabled": false, + "info": "" + }, + { + "id": "9a22e67a.378818", + "type": "tab", + "label": "MQTT Receive", + "disabled": false, + "info": "" + }, + { + "id": "1eaf21c8.f7a21e", + "type": "tab", + "label": "Hardware Settings", + "disabled": false, + "info": "" + }, + { + "id": "1c24ad9c.bebec2", + "type": "subflow", + "name": "Config", + "info": "An input to this subflow will get the configuration to be saved to disk.\n\nOn startup, this node outputs the loaded configuration", + "category": "", + "in": [ + { + "x": 220, + "y": 160, + "wires": [ + { + "id": "3ad9835.08c937c" + } + ] + } + ], + "out": [ + { + "x": 1040, + "y": 60, + "wires": [ + { + "id": "ad541674.4791c8", + "port": 0 + }, + { + "id": "f439663c.8abd3", + "port": 0 + } + ] + } + ], + "env": [], + "color": "#DDAA99" + }, + { + "id": "4ed26b8b.253504", + "type": "subflow", + "name": "Save hardware config", + "info": "", + "category": "", + "in": [ + { + "x": 40, + "y": 40, + "wires": [ + { + "id": "53d163be.47cf24" + } + ] + } + ], + "out": [], + "env": [], + "meta": {}, + "color": "#DDAA99" + }, + { + "id": "b7861ce703215a01", + "type": "subflow", + "name": "Load hardware config", + "info": "", + "category": "", + "in": [ + { + "x": 40, + "y": 40, + "wires": [ + { + "id": "0f16258953fae292" + } + ] + } + ], + "out": [ + { + "x": 900, + "y": 40, + "wires": [ + { + "id": "d0fbcd200cd09981", + "port": 0 + } + ] + } + ], + "env": [], + "meta": {}, + "color": "#DDAA99" + }, + { + "id": "833bc5bb.217ba8", + "type": "ui_group", + "name": "Preview", + "tab": "181bb236.1e94be", + "order": 1, + "disp": true, + "width": 18, + "collapse": false + }, + { + "id": "3a6bb13f.c9703e", + "type": "ui_tab", + "name": "Home", + "icon": "home", + "order": 1, + "disabled": false, + "hidden": false + }, + { + "id": "181bb236.1e94be", + "type": "ui_tab", + "name": "Optic Configuration", + "icon": "fa-eye", + "order": 3, + "disabled": false, + "hidden": false + }, + { + "id": "c9194f02.9d5e9", + "type": "ui_tab", + "name": "Fluidic Acquisition", + "icon": "fa-flask", + "order": 4, + "disabled": false, + "hidden": false + }, + { + "id": "8d16beb8.9b3fb", + "type": "ui_tab", + "name": "Segmentation", + "icon": "fa-crop", + "order": 5, + "disabled": false, + "hidden": false + }, + { + "id": "d9cd733b.ab73d", + "type": "ui_tab", + "name": "System Monitoring", + "icon": "fa-thermometer-full", + "order": 7, + "disabled": false, + "hidden": false + }, + { + "id": "4248342d.e55fac", + "type": "ui_group", + "name": "Optic Characterization", + "tab": "181bb236.1e94be", + "order": 4, + "disp": true, + "width": "6", + "collapse": false + }, + { + "id": "858a0e3c.987fe", + "type": "ui_group", + "name": "Preview", + "tab": "c9194f02.9d5e9", + "order": 1, + "disp": true, + "width": 10, + "collapse": false + }, + { + "id": "64903b47.4034e4", + "type": "ui_group", + "name": "Navigation", + "tab": "8d16beb8.9b3fb", + "order": 3, + "disp": false, + "width": "6", + "collapse": false + }, + { + "id": "3da7da8f.179606", + "type": "ui_group", + "name": "Metrics", + "tab": "d9cd733b.ab73d", + "order": 1, + "disp": true, + "width": "24", + "collapse": true, + "className": "" + }, + { + "id": "cc8bc4eb.651868", + "type": "ui_base", + "theme": { + "name": "theme-dark", + "lightTheme": { + "default": "#0094CE", + "baseColor": "#5900ce", + "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", + "edited": false, + "reset": false + }, + "darkTheme": { + "default": "#097479", + "baseColor": "#097479", + "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", + "edited": true, + "reset": false + }, + "customTheme": { + "name": "Untitled Theme 1", + "default": "#4B7930", + "baseColor": "#4B7930", + "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif" + }, + "themeState": { + "base-color": { + "default": "#097479", + "value": "#097479", + "edited": true + }, + "page-titlebar-backgroundColor": { + "value": "#097479", + "edited": false + }, + "page-backgroundColor": { + "value": "#111111", + "edited": false + }, + "page-sidebar-backgroundColor": { + "value": "#333333", + "edited": false + }, + "group-textColor": { + "value": "#0eb8c0", + "edited": false + }, + "group-borderColor": { + "value": "#555555", + "edited": false + }, + "group-backgroundColor": { + "value": "#333333", + "edited": false + }, + "widget-textColor": { + "value": "#eeeeee", + "edited": false + }, + "widget-backgroundColor": { + "value": "#097479", + "edited": false + }, + "widget-borderColor": { + "value": "#333333", + "edited": false + }, + "base-font": { + "value": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif" + } + }, + "angularTheme": { + "primary": "indigo", + "accents": "blue", + "warn": "red", + "background": "grey", + "palette": "light" + } + }, + "site": { + "name": "PlanktoScope", + "hideToolbar": "false", + "allowSwipe": "false", + "lockMenu": "false", + "allowTempTheme": "true", + "dateFormat": "Y-MM-DD", + "sizes": { + "sx": 55, + "sy": 55, + "gx": 4, + "gy": 4, + "cx": 4, + "cy": 4, + "px": 4, + "py": 4 + } + } + }, + { + "id": "36739a35.7cce36", + "type": "ui_tab", + "name": "Gallery", + "icon": "fa-file-image-o", + "order": 6, + "disabled": false, + "hidden": false + }, + { + "id": "c0ebfc57.42527", + "type": "ui_group", + "name": "Group 1", + "tab": "36739a35.7cce36", + "order": 1, + "disp": false, + "width": "24", + "collapse": false, + "className": "" + }, + { + "id": "737ec584.2eea2c", + "type": "ui_tab", + "name": "Sample", + "icon": "fa-eyedropper", + "order": 2, + "disabled": false, + "hidden": false + }, + { + "id": "6f97e7ae.270c48", + "type": "ui_group", + "name": "Group 1", + "tab": "3a6bb13f.c9703e", + "order": 1, + "disp": false, + "width": "4", + "collapse": false + }, + { + "id": "3e1ba03d.f01d8", + "type": "ui_group", + "name": "Sample Identification", + "tab": "737ec584.2eea2c", + "order": 1, + "disp": true, + "width": "10", + "collapse": false + }, + { + "id": "4e0cd5ea.17e59c", + "type": "ui_group", + "name": "Group 2", + "tab": "3a6bb13f.c9703e", + "order": 2, + "disp": false, + "width": "4", + "collapse": false + }, + { + "id": "ef590206.24f6", + "type": "ui_group", + "name": "Group 3", + "tab": "3a6bb13f.c9703e", + "order": 3, + "disp": false, + "width": "4", + "collapse": false + }, + { + "id": "ae8f6620.073358", + "type": "ui_group", + "name": "Group 4", + "tab": "3a6bb13f.c9703e", + "order": 4, + "disp": false, + "width": "4", + "collapse": false + }, + { + "id": "196518b2.4d53b7", + "type": "ui_group", + "name": "Group 5", + "tab": "3a6bb13f.c9703e", + "order": 5, + "disp": false, + "width": "4", + "collapse": false + }, + { + "id": "777a7c33.fcd804", + "type": "ui_group", + "name": "Group 6", + "tab": "3a6bb13f.c9703e", + "order": 6, + "disp": false, + "width": "4", + "collapse": false + }, + { + "id": "cef1e703.bcf3c8", + "type": "ui_group", + "name": "Sample Location", + "tab": "737ec584.2eea2c", + "order": 3, + "disp": false, + "width": "10", + "collapse": false + }, + { + "id": "5517c651.b2f668", + "type": "ui_group", + "name": "Validation", + "tab": "737ec584.2eea2c", + "order": 5, + "disp": false, + "width": 10, + "collapse": false + }, + { + "id": "fbd92986.1028c8", + "type": "ui_group", + "name": "Focus Adjustment", + "tab": "181bb236.1e94be", + "order": 2, + "disp": true, + "width": 4, + "collapse": false + }, + { + "id": "707d9797.c8e798", + "type": "ui_group", + "name": "Fluidic Manual Manipulation", + "tab": "181bb236.1e94be", + "order": 5, + "disp": true, + "width": 4, + "collapse": false + }, + { + "id": "7a0b4877.a5d268", + "type": "ui_group", + "name": "Navigation", + "tab": "181bb236.1e94be", + "order": 6, + "disp": false, + "width": 4, + "collapse": false + }, + { + "id": "4322c187.e73e5", + "type": "ui_group", + "name": "Acquisition", + "tab": "c9194f02.9d5e9", + "order": 3, + "disp": true, + "width": 10, + "collapse": false + }, + { + "id": "b7919ae2.c01788", + "type": "ui_group", + "name": "Navigation", + "tab": "c9194f02.9d5e9", + "order": 6, + "disp": false, + "width": "10", + "collapse": false + }, + { + "id": "b5d61bc7.54fe48", + "type": "ui_group", + "name": "Statistics", + "tab": "c9194f02.9d5e9", + "order": 4, + "disp": true, + "width": "10", + "collapse": false + }, + { + "id": "1be83144.4fe4bf", + "type": "ui_group", + "name": "Dashboard Errors", + "tab": "2489e51c.eed77a", + "order": 2, + "disp": true, + "width": "12", + "collapse": true, + "className": "" + }, + { + "id": "3ca00bf9.e5cac4", + "type": "ui_group", + "name": "Navigation", + "tab": "d9cd733b.ab73d", + "order": 7, + "disp": true, + "width": 6, + "collapse": false + }, + { + "id": "8dc3722c.06efa8", + "type": "mqtt-broker", + "name": "", + "broker": "0.0.0.0", + "port": "1883", + "clientid": "Client_node", + "autoConnect": true, + "usetls": false, + "compatmode": false, + "protocolVersion": 4, + "keepalive": "60", + "cleansession": true, + "birthTopic": "", + "birthQos": "0", + "birthPayload": "", + "closeTopic": "", + "closeQos": "0", + "closePayload": "", + "willTopic": "", + "willQos": "0", + "willPayload": "" + }, + { + "id": "abeb6dad.635a2", + "type": "ui_group", + "name": "Control", + "tab": "8d16beb8.9b3fb", + "order": 1, + "disp": true, + "width": 10, + "collapse": false + }, + { + "id": "cf5d9f0e.d57e7", + "type": "ui_group", + "name": "Net Metadata", + "tab": "737ec584.2eea2c", + "order": 4, + "disp": false, + "width": "10", + "collapse": false + }, + { + "id": "ce9e278.781eed8", + "type": "ui_group", + "name": "Information", + "tab": "d9cd733b.ab73d", + "order": 5, + "disp": true, + "width": 6, + "collapse": false + }, + { + "id": "70de8209.68416c", + "type": "ui_group", + "name": "Status", + "tab": "c9194f02.9d5e9", + "order": 5, + "disp": true, + "width": 10, + "collapse": false + }, + { + "id": "46be9c86.dea684", + "type": "ui_group", + "name": "Status", + "tab": "8d16beb8.9b3fb", + "order": 2, + "disp": true, + "width": 10, + "collapse": false + }, + { + "id": "8c38a81e.9897a8", + "type": "ui_group", + "name": "Camera Settings", + "tab": "181bb236.1e94be", + "order": 3, + "disp": true, + "width": 6, + "collapse": false + }, + { + "id": "52d1b77.28369c8", + "type": "ui_group", + "name": "USB Backup", + "tab": "d9cd733b.ab73d", + "order": 6, + "disp": true, + "width": "6", + "collapse": true + }, + { + "id": "a7d64879.38298", + "type": "ui_group", + "name": "Logs", + "tab": "2489e51c.eed77a", + "order": 1, + "disp": true, + "width": "12", + "collapse": true, + "className": "" + }, + { + "id": "9e409235.73cd7", + "type": "ui_group", + "name": "Add a new network", + "tab": "1b49ae0f.602d6a", + "order": 2, + "disp": true, + "width": "6", + "collapse": false + }, + { + "id": "919923a3.d10868", + "type": "ui_group", + "name": "Current Connection", + "tab": "1b49ae0f.602d6a", + "order": 1, + "disp": true, + "width": "6", + "collapse": false + }, + { + "id": "1b49ae0f.602d6a", + "type": "ui_tab", + "name": "Wifi", + "icon": "wifi", + "order": 8, + "disabled": false, + "hidden": false + }, + { + "id": "2489e51c.eed77a", + "type": "ui_tab", + "name": "Administration", + "icon": "dashboard", + "order": 9, + "disabled": false, + "hidden": false + }, + { + "id": "b0fb559a.6966a8", + "type": "ui_tab", + "name": "Hardware Settings", + "icon": "fa-cogs", + "disabled": false, + "hidden": false + }, + { + "id": "6be36295.0ab324", + "type": "ui_group", + "name": "Settings", + "tab": "b0fb559a.6966a8", + "order": 1, + "disp": false, + "width": "8", + "collapse": false, + "className": "" + }, + { + "id": "fc5e4e6f.5b1c8", + "type": "ui_group", + "name": "GPS Status", + "tab": "737ec584.2eea2c", + "order": 6, + "disp": true, + "width": 10, + "collapse": false + }, + { + "id": "f3ca28ef.4df0a8", + "type": "ui_group", + "name": "Shutdown", + "tab": "3a6bb13f.c9703e", + "order": 7, + "disp": true, + "width": 4, + "collapse": false + }, + { + "id": "3dfd8a69.69ed56", + "type": "ui_spacer", + "name": "spacer", + "group": "f3ca28ef.4df0a8", + "order": 3, + "width": 4, + "height": 1 + }, + { + "id": "cfe2288f.a8862", + "type": "ui_group", + "name": "GPS Status", + "tab": "d9cd733b.ab73d", + "order": 8, + "disp": true, + "width": "6", + "collapse": false + }, + { + "id": "72a9216.2ff48e", + "type": "ui_spacer", + "name": "spacer", + "group": "4322c187.e73e5", + "order": 8, + "width": 10, + "height": 1 + }, + { + "id": "1b664927.c91d1f", + "type": "ui_spacer", + "name": "spacer", + "group": "b5d61bc7.54fe48", + "order": 2, + "width": 2, + "height": 1 + }, + { + "id": "1a663b6a.ab5805", + "type": "ui_spacer", + "name": "spacer", + "group": "b5d61bc7.54fe48", + "order": 4, + "width": 2, + "height": 1 + }, + { + "id": "8eeed8d8.ad9098", + "type": "ui_spacer", + "name": "spacer", + "group": "b5d61bc7.54fe48", + "order": 5, + "width": 2, + "height": 1 + }, + { + "id": "be1c5ce7.004e", + "type": "ui_spacer", + "name": "spacer", + "group": "b5d61bc7.54fe48", + "order": 6, + "width": 2, + "height": 1 + }, + { + "id": "c2fe38e9.555e3", + "type": "ui_spacer", + "name": "spacer", + "group": "b5d61bc7.54fe48", + "order": 7, + "width": 2, + "height": 1 + }, + { + "id": "89bd18b7.c779a8", + "type": "ui_spacer", + "name": "spacer", + "group": "b5d61bc7.54fe48", + "order": 8, + "width": 2, + "height": 1 + }, + { + "id": "3cbbfa5d.efa636", + "type": "ui_spacer", + "name": "spacer", + "group": "b7919ae2.c01788", + "order": 2, + "width": 5, + "height": 1 + }, + { + "id": "97148e8d8e298f1a", + "type": "ui_spacer", + "z": "cb95299c.2817c8", + "name": "spacer", + "group": "abeb6dad.635a2", + "order": 7, + "width": 10, + "height": 1 + }, + { + "id": "3b2eccc574e6a9ae", + "type": "ui_spacer", + "z": "cb95299c.2817c8", + "name": "spacer", + "group": "abeb6dad.635a2", + "order": 11, + "width": 1, + "height": 1 + }, + { + "id": "bbd6431d97c86f97", + "type": "ui_spacer", + "z": "cb95299c.2817c8", + "name": "spacer", + "group": "46be9c86.dea684", + "order": 4, + "width": 3, + "height": 1 + }, + { + "id": "5f98f5f140f0ecde", + "type": "ui_spacer", + "z": "cb95299c.2817c8", + "name": "spacer", + "group": "46be9c86.dea684", + "order": 6, + "width": 3, + "height": 1 + }, + { + "id": "7bc0a4c416e4545c", + "type": "ui_group", + "name": "Culture Date and Time", + "tab": "737ec584.2eea2c", + "order": 2, + "disp": true, + "width": "10", + "collapse": false, + "className": "" + }, + { + "id": "6c31ad948a9d62fd", + "type": "ui_spacer", + "z": "b771c342.49603", + "name": "spacer", + "group": "3e1ba03d.f01d8", + "order": 5, + "width": 10, + "height": 1 + }, + { + "id": "d65a6ccdeb9d35d6", + "type": "ui_spacer", + "z": "b771c342.49603", + "name": "spacer", + "group": "fc5e4e6f.5b1c8", + "order": 3, + "width": 1, + "height": 1 + }, + { + "id": "6465bdd5.15eb8c", + "type": "file in", + "z": "1c24ad9c.bebec2", + "name": "", + "filename": "/home/pi/PlanktoScope/config.json", + "filenameType": "str", + "format": "utf8", + "chunk": false, + "sendError": false, + "encoding": "none", + "x": 560, + "y": 60, + "wires": [ + [ + "15ceb135.6628bf" + ] + ], + "info": "# PlanktoScope Help\nThis Node will read the content of the file named **config.txt** containing all the input placeholders.\n" + }, + { + "id": "15ceb135.6628bf", + "type": "json", + "z": "1c24ad9c.bebec2", + "name": "config.json", + "property": "payload", + "action": "", + "pretty": false, + "x": 730, + "y": 60, + "wires": [ + [ + "ad541674.4791c8" + ] + ] + }, + { + "id": "7205d267.36adcc", + "type": "file", + "z": "1c24ad9c.bebec2", + "name": "", + "filename": "/home/pi/PlanktoScope/config.json", + "appendNewline": true, + "createDir": true, + "overwriteFile": "true", + "encoding": "none", + "x": 990, + "y": 160, + "wires": [ + [] + ] + }, + { + "id": "2e6ddf51.c0dba", + "type": "json", + "z": "1c24ad9c.bebec2", + "name": "config.json", + "property": "payload", + "action": "str", + "pretty": true, + "x": 730, + "y": 160, + "wires": [ + [ + "7205d267.36adcc" + ] + ] + }, + { + "id": "ad541674.4791c8", + "type": "function", + "z": "1c24ad9c.bebec2", + "name": "Global Set", + "func": "global.set(\"config_keys\", Object.keys(msg.payload));\n\nfor (const key in msg.payload) {\n global.set(key, msg.payload[key]);\n}\n\nreturn msg;", + "outputs": 1, + "timeout": "", + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 910, + "y": 60, + "wires": [ + [] + ] + }, + { + "id": "3e9a33c.141384c", + "type": "inject", + "z": "1c24ad9c.bebec2", + "name": "Load config", + "props": [ + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": 0.1, + "topic": "", + "payloadType": "str", + "x": 230, + "y": 60, + "wires": [ + [ + "6465bdd5.15eb8c" + ] + ] + }, + { + "id": "3ad9835.08c937c", + "type": "function", + "z": "1c24ad9c.bebec2", + "name": "get config payload", + "func": "keys = global.get(\"config_keys\")\n\nvar payload = {}\n\nkeys.forEach(function(item, index, array) {\n payload[item] = global.get(item);\n})\n\nreturn {\"payload\": payload};", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 410, + "y": 160, + "wires": [ + [ + "2e6ddf51.c0dba" + ] + ] + }, + { + "id": "f439663c.8abd3", + "type": "ui_ui_control", + "z": "1c24ad9c.bebec2", + "name": "Connect Event", + "events": "connect", + "x": 900, + "y": 100, + "wires": [ + [] + ] + }, + { + "id": "82099021.9ceb08", + "type": "file", + "z": "4ed26b8b.253504", + "name": "", + "filename": "/home/pi/PlanktoScope/hardware.json", + "appendNewline": true, + "createDir": true, + "overwriteFile": "true", + "encoding": "none", + "x": 660, + "y": 40, + "wires": [ + [] + ] + }, + { + "id": "bb0a8725.a1849", + "type": "json", + "z": "4ed26b8b.253504", + "name": "Create JSON", + "property": "payload", + "action": "str", + "pretty": true, + "x": 490, + "y": 40, + "wires": [ + [ + "82099021.9ceb08" + ] + ] + }, + { + "id": "53d163be.47cf24", + "type": "function", + "z": "4ed26b8b.253504", + "name": "Update and retrieve hardware_conf", + "func": "// change global\nhardware_conf = global.get(\"hardware_conf\");\n\nif (msg.topic == \"process_pixel_fixed\" && msg.payload == 0){\n delete hardware_conf[msg.topic]\n delete msg.topic\n}\n\nif (msg.topic !== null && msg.topic !== undefined){\n hardware_conf[msg.topic] = msg.payload;\n global.set(\"hardware_conf\", hardware_conf);\n}\n\nreturn {\"payload\": hardware_conf};", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 240, + "y": 40, + "wires": [ + [ + "bb0a8725.a1849" + ] + ] + }, + { + "id": "0f16258953fae292", + "type": "file in", + "z": "b7861ce703215a01", + "name": "", + "filename": "/home/pi/PlanktoScope/hardware.json", + "filenameType": "str", + "format": "utf8", + "chunk": false, + "sendError": false, + "encoding": "none", + "allProps": false, + "x": 250, + "y": 40, + "wires": [ + [ + "81c516291ab19acd" + ] + ], + "info": "# PlanktoScope Help\nThis Node will read the content of the file named **config.txt** containing all the input placeholders.\n" + }, + { + "id": "81c516291ab19acd", + "type": "json", + "z": "b7861ce703215a01", + "name": "Parse JSON", + "property": "payload", + "action": "", + "pretty": false, + "x": 510, + "y": 40, + "wires": [ + [ + "d0fbcd200cd09981" + ] + ] + }, + { + "id": "d0fbcd200cd09981", + "type": "change", + "z": "b7861ce703215a01", + "name": "", + "rules": [ + { + "t": "set", + "p": "hardware_conf", + "pt": "global", + "to": "payload", + "tot": "msg" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 730, + "y": 40, + "wires": [ + [] + ] + }, + { + "id": "4e78af2d.90be7", + "type": "ui_ui_control", + "z": "eaae323a.31b3", + "name": "", + "events": "change", + "x": 440, + "y": 160, + "wires": [ + [] + ] + }, + { + "id": "7789839d.69b48c", + "type": "ui_template", + "z": "eaae323a.31b3", + "group": "4e0cd5ea.17e59c", + "name": "Optic Configuration", + "order": 1, + "width": 4, + "height": 4, + "format": "\n \n
Optic Configuration
\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": false, + "templateScope": "local", + "x": 130, + "y": 100, + "wires": [ + [ + "4e78af2d.90be7" + ] + ] + }, + { + "id": "6ea6c306.f9c12c", + "type": "ui_template", + "z": "eaae323a.31b3", + "group": "ef590206.24f6", + "name": "Fluidic Acquisition", + "order": 1, + "width": 4, + "height": 4, + "format": "\n \n
Fluidic Acquisition
\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": false, + "templateScope": "local", + "x": 130, + "y": 140, + "wires": [ + [ + "4e78af2d.90be7" + ] + ] + }, + { + "id": "bb9eb153.9e36c", + "type": "ui_template", + "z": "eaae323a.31b3", + "group": "ae8f6620.073358", + "name": "Segmentation", + "order": 1, + "width": 4, + "height": 4, + "format": "\n \n
Segmentation
\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": false, + "templateScope": "local", + "x": 140, + "y": 180, + "wires": [ + [ + "4e78af2d.90be7" + ] + ] + }, + { + "id": "eaf8ee7f.96f44", + "type": "ui_template", + "z": "eaae323a.31b3", + "group": "196518b2.4d53b7", + "name": "Gallery", + "order": 1, + "width": 4, + "height": 4, + "format": "\n \n
Gallery
\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": false, + "templateScope": "local", + "x": 160, + "y": 220, + "wires": [ + [ + "4e78af2d.90be7" + ] + ] + }, + { + "id": "c1b1469.9650eb8", + "type": "ui_template", + "z": "eaae323a.31b3", + "group": "777a7c33.fcd804", + "name": "System Monitoring", + "order": 1, + "width": 4, + "height": 4, + "format": "\n \n
System Monitoring
\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": false, + "templateScope": "local", + "x": 130, + "y": 260, + "wires": [ + [ + "4e78af2d.90be7" + ] + ] + }, + { + "id": "abafd6e6.04a5f8", + "type": "ui_template", + "z": "eaae323a.31b3", + "group": "6f97e7ae.270c48", + "name": "Sample", + "order": 1, + "width": 4, + "height": 4, + "format": "\n \n
Sample
\n
\n In doubt? Start Here!\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": false, + "templateScope": "local", + "x": 160, + "y": 60, + "wires": [ + [ + "4e78af2d.90be7" + ] + ] + }, + { + "id": "dab82064.26a8d", + "type": "ui_button", + "z": "eaae323a.31b3", + "name": "Unlock button", + "group": "f3ca28ef.4df0a8", + "order": 2, + "width": 0, + "height": 0, + "passthru": false, + "label": "Unlock button", + "tooltip": "", + "color": "", + "bgcolor": "", + "icon": "", + "payload": "shutdown", + "payloadType": "flow", + "topic": "", + "x": 120, + "y": 380, + "wires": [ + [ + "6c3a3b4.78cad44" + ] + ] + }, + { + "id": "1c658761.b852a1", + "type": "ui_toast", + "z": "eaae323a.31b3", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "YES PLEASE", + "cancel": "NO!", + "raw": false, + "topic": "Are you sure?", + "name": "Confirmation message", + "x": 800, + "y": 380, + "wires": [ + [ + "8f1b8e23.daafe" + ] + ] + }, + { + "id": "a48ff63f.db5e18", + "type": "inject", + "z": "eaae323a.31b3", + "name": "disabled", + "props": [ + { + "p": "enabled", + "v": "false", + "vt": "bool" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": 0.1, + "topic": "", + "x": 140, + "y": 420, + "wires": [ + [ + "d58039a9.6e7928" + ] + ] + }, + { + "id": "b67a7147.65fcd8", + "type": "ui_button", + "z": "eaae323a.31b3", + "name": "Shutdown button", + "group": "f3ca28ef.4df0a8", + "order": 4, + "width": 0, + "height": 0, + "passthru": false, + "label": "Shutdown", + "tooltip": "", + "color": "", + "bgcolor": "#AD1625", + "icon": "fa-power-off fa-2x", + "payload": "Do you want to turn the machine off now?", + "payloadType": "str", + "topic": "", + "x": 550, + "y": 380, + "wires": [ + [ + "1c658761.b852a1" + ] + ] + }, + { + "id": "d58039a9.6e7928", + "type": "change", + "z": "eaae323a.31b3", + "name": "", + "rules": [ + { + "t": "set", + "p": "shutdown", + "pt": "flow", + "to": "false", + "tot": "bool" + }, + { + "t": "set", + "p": "enabled", + "pt": "msg", + "to": "shutdown", + "tot": "flow" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 320, + "y": 420, + "wires": [ + [ + "b67a7147.65fcd8" + ] + ] + }, + { + "id": "6c3a3b4.78cad44", + "type": "function", + "z": "eaae323a.31b3", + "name": "Toggle", + "func": "flow.set(\"shutdown\", !flow.get(\"shutdown\"))\nmsg.enabled = flow.get(\"shutdown\")\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 290, + "y": 380, + "wires": [ + [ + "b67a7147.65fcd8" + ] + ] + }, + { + "id": "d1153ad6.40d738", + "type": "ui_template", + "z": "eaae323a.31b3", + "group": "f3ca28ef.4df0a8", + "name": "Shutdown information", + "order": 1, + "width": 0, + "height": 0, + "format": "
To prevent data corruption, please always shutdown the machine before unplugging the unit.\n

\nRemember to first unlock the shutdown button.\n
", + "storeOutMessages": true, + "fwdInMessages": false, + "resendOnRefresh": true, + "templateScope": "local", + "x": 120, + "y": 320, + "wires": [ + [] + ] + }, + { + "id": "e08cfcb8.2a67e8", + "type": "link out", + "z": "eaae323a.31b3", + "name": "Home shutdown button", + "links": [ + "b81b990a.d4dca" + ], + "x": 715, + "y": 500, + "wires": [] + }, + { + "id": "ce7087fc.dcc9e8", + "type": "ui_toast", + "z": "eaae323a.31b3", + "position": "dialog", + "displayTime": "10", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "topic": "Turning off now!", + "name": "Shutdown message", + "x": 580, + "y": 540, + "wires": [ + [] + ] + }, + { + "id": "7d1626a0.deb85", + "type": "change", + "z": "eaae323a.31b3", + "name": "shutdown!", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "shutdown", + "tot": "str" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 310, + "y": 500, + "wires": [ + [ + "e08cfcb8.2a67e8" + ] + ] + }, + { + "id": "8f1b8e23.daafe", + "type": "switch", + "z": "eaae323a.31b3", + "name": "", + "property": "payload", + "propertyType": "msg", + "rules": [ + { + "t": "eq", + "v": "NO!", + "vt": "str" + }, + { + "t": "else" + } + ], + "checkall": "true", + "repair": false, + "outputs": 2, + "x": 150, + "y": 500, + "wires": [ + [ + "d58039a9.6e7928" + ], + [ + "7d1626a0.deb85", + "281a56c9.ec7902" + ] + ] + }, + { + "id": "281a56c9.ec7902", + "type": "change", + "z": "eaae323a.31b3", + "name": "Shutdown message", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "Please wait a minute before disconnecting the machine from its power supply!", + "tot": "str" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 340, + "y": 540, + "wires": [ + [ + "ce7087fc.dcc9e8" + ] + ] + }, + { + "id": "57db4f6279b5afe0", + "type": "comment", + "z": "eaae323a.31b3", + "name": "LICENSE", + "info": "Copyright 2022 Thibaut Pollina and Romain Bazile\nLicensed under GPL v3.0", + "x": 140, + "y": 600, + "wires": [] + }, + { + "id": "4557d689.a4fa88", + "type": "ui_text_input", + "z": "b771c342.49603", + "name": "sample_ship", + "label": "Name of the ship", + "tooltip": "", + "group": "3e1ba03d.f01d8", + "order": 2, + "width": 0, + "height": 0, + "passthru": true, + "mode": "text", + "delay": "300", + "topic": "sample_ship", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 670, + "y": 80, + "wires": [ + [ + "9f501f49.45645" + ] + ] + }, + { + "id": "fcfc31ae.af3af", + "type": "ui_dropdown", + "z": "b771c342.49603", + "name": "sample_sampling_gear", + "label": "Sampling gear*", + "tooltip": "", + "place": "Choose from list", + "group": "3e1ba03d.f01d8", + "order": 6, + "width": 0, + "height": 0, + "passthru": true, + "multiple": false, + "options": [ + { + "label": "High Speed Net", + "value": "net_hsn", + "type": "str" + }, + { + "label": "Tara Decknet", + "value": "net_decknet", + "type": "str" + }, + { + "label": "Plankton net", + "value": "net", + "type": "str" + }, + { + "label": "Niskin bottle 12L", + "value": "niskin_12L", + "type": "str" + }, + { + "label": "Niskin bottle 24L", + "value": "niskin_24L", + "type": "str" + }, + { + "label": "Pass Hull", + "value": "pass_hull", + "type": "str" + }, + { + "label": "Single location (with net or bucket)", + "value": "single_location", + "type": "str" + }, + { + "label": "Lab culture", + "value": "culture", + "type": "str" + }, + { + "label": "Test", + "value": "test", + "type": "str" + } + ], + "payload": "", + "topic": "sample_sampling_gear", + "topicType": "str", + "className": "", + "x": 630, + "y": 200, + "wires": [ + [ + "9f501f49.45645", + "46eb1bf8.3dc5f4", + "3ac7b631f5d8ef90" + ] + ] + }, + { + "id": "82c5fc77.59c97", + "type": "ui_text_input", + "z": "b771c342.49603", + "name": "sample_operator", + "label": "Name of the operator*", + "tooltip": "", + "group": "3e1ba03d.f01d8", + "order": 3, + "width": 0, + "height": 0, + "passthru": true, + "mode": "text", + "delay": "300", + "topic": "sample_operator", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 650, + "y": 160, + "wires": [ + [ + "9f501f49.45645" + ] + ] + }, + { + "id": "9c882b37.fde668", + "type": "ui_text_input", + "z": "b771c342.49603", + "name": "sample_project", + "label": "Name of the project*", + "tooltip": "", + "group": "3e1ba03d.f01d8", + "order": 1, + "width": 0, + "height": 0, + "passthru": true, + "mode": "text", + "delay": "300", + "topic": "sample_project", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 660, + "y": 40, + "wires": [ + [ + "9f501f49.45645" + ] + ] + }, + { + "id": "94eb4221.9b92c", + "type": "ui_text_input", + "z": "b771c342.49603", + "name": "sample_id", + "label": "Station ID*", + "tooltip": "", + "group": "3e1ba03d.f01d8", + "order": 4, + "width": 0, + "height": 0, + "passthru": true, + "mode": "text", + "delay": "300", + "topic": "sample_id", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 670, + "y": 120, + "wires": [ + [ + "9f501f49.45645" + ] + ] + }, + { + "id": "9f501f49.45645", + "type": "function", + "z": "b771c342.49603", + "name": "set global", + "func": "global.set(msg.topic,msg.payload);", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 1080, + "y": 200, + "wires": [ + [] + ] + }, + { + "id": "222c851d.5d0a3a", + "type": "ui_ui_control", + "z": "b771c342.49603", + "name": "", + "events": "change", + "x": 400, + "y": 880, + "wires": [ + [] + ] + }, + { + "id": "52f6b103.1efb6", + "type": "ui_toast", + "z": "b771c342.49603", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "topic": "", + "name": "", + "x": 710, + "y": 980, + "wires": [ + [] + ] + }, + { + "id": "986d960a.c75908", + "type": "function", + "z": "b771c342.49603", + "name": "Check form", + "func": "var sample_project= global.get(\"sample_project\");\nvar sample_id= global.get(\"sample_id\");\nvar sample_operator= global.get(\"sample_operator\");\nvar sample_sampling_gear= global.get(\"sample_sampling_gear\");\nvar object_lat= global.get(\"object_lat\");\nvar object_lon= global.get(\"object_lon\");\nvar object_date= global.get(\"object_date\");\nvar object_time= global.get(\"object_time\");\nif (sample_project === undefined || sample_project === \"\") {\n msg.topic = \"Missing entry :\"\n msg.payload = \"Sample project\"\n return [null, msg];\n}\n\nelse if (sample_id === undefined || sample_id === \"\") {\n msg.topic = \"Missing entry :\"\n msg.payload = \"Sample ID\"\n return [null, msg];\n}\n\nelse if (sample_operator === undefined || sample_operator === \"\") {\n msg.topic = \"Missing entry :\"\n msg.payload = \"Sample operator\"\n return [null, msg];\n}\n\nelse if (sample_sampling_gear === undefined || sample_sampling_gear === \"\") {\n msg.topic = \"Missing entry :\"\n msg.payload = \"Sample sampling gear\"\n return [null, msg];\n}\n\nelse if (object_lat === undefined || object_lat === null) {\n msg.topic = \"Missing entry :\"\n msg.payload = \"Latitude of sample\"\n return [null, msg];\n}\n\nelse if (object_lon === undefined || object_lon === null) {\n msg.topic = \"Missing entry :\"\n msg.payload = \"Longitude of sample\"\n return [null, msg];\n}\n\nelse if (object_date === undefined || object_date === \"\") {\n msg.topic = \"Missing entry :\"\n msg.payload = \"Date of sample\"\n return [null, msg];\n}\n\nelse if (object_time === undefined || object_time === \"\") {\n msg.topic = \"Missing entry :\"\n msg.payload = \"Time of sample\"\n return [null, msg];\n}\nelse if (sample_sampling_gear.startsWith(\"net\")){\n var object_lat_end = global.get(\"object_lat_end\");\n var object_lon_end = global.get(\"object_lon_end\");\n var object_date_end = global.get(\"object_date_end\");\n var object_time_end = global.get(\"object_time_end\");\n var sample_gear_net_opening = global.get(\"sample_gear_net_opening\");\n\n if (object_lat_end === undefined || object_lat_end === null) {\n msg.topic = \"Missing entry :\"\n msg.payload = \"Latitude of retrieval\"\n return [null, msg];\n }\n \n else if (object_lon_end === undefined || object_lon_end === null) {\n msg.topic = \"Missing entry :\"\n msg.payload = \"Longitude of retrieval\"\n return [null, msg];\n }\n \n else if (object_date_end === undefined || object_date_end === \"\") {\n msg.topic = \"Missing entry :\"\n msg.payload = \"Date of retrieval\"\n return [null, msg];\n }\n \n else if (object_time_end === undefined || object_time_end === \"\") {\n msg.topic = \"Missing entry :\"\n msg.payload = \"Time of retrieval\"\n return [null, msg];\n }\n \n else if (sample_gear_net_opening === undefined || sample_gear_net_opening === \"\") {\n msg.topic = \"Missing entry :\"\n msg.payload = \"Net opening dimension\"\n return [null, msg];\n }\n \n if (sample_sampling_gear == \"net_decknet\"){\n var sample_total_volume = global.get(\"sample_total_volume\");\n if (sample_total_volume === undefined || sample_total_volume === \"\") {\n msg.topic = \"Missing entry :\"\n msg.payload = \"Decknet flowmeter readings\"\n return [null, msg];\n }\n }\n}\nmsg.topic = \"config_save\"\nmsg.payload={\"tab\":\"Optic Configuration\"};\n\nreturn [msg, null];", + "outputs": 2, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 470, + "y": 940, + "wires": [ + [ + "726a7822.cd6298", + "e2b277c1.07283" + ], + [ + "52f6b103.1efb6" + ] + ], + "outputLabels": [ + "message", + "error" + ] + }, + { + "id": "18f44504.cac66b", + "type": "gpsd", + "z": "b771c342.49603", + "name": "", + "hostname": "localhost", + "port": "2947", + "tpv": true, + "sky": false, + "info": false, + "device": false, + "gst": false, + "att": false, + "x": 250, + "y": 1240, + "wires": [ + [ + "258b4562.9f778a", + "54e37580.fdc31c", + "cc21ca16.b92928", + "4a4de52c.cf2884", + "73c4a14a.9b93c8" + ] + ] + }, + { + "id": "726a7822.cd6298", + "type": "ui_ui_control", + "z": "b771c342.49603", + "name": "", + "events": "change", + "x": 700, + "y": 900, + "wires": [ + [] + ] + }, + { + "id": "16de754c.cc969b", + "type": "ui_button", + "z": "b771c342.49603", + "name": "", + "group": "5517c651.b2f668", + "order": 1, + "width": 5, + "height": 1, + "passthru": false, + "label": "Previous", + "tooltip": "", + "color": "#097479", + "bgcolor": "white", + "icon": "keyboard_return", + "payload": "{\"tab\":\"Home\"}", + "payloadType": "json", + "topic": "", + "x": 240, + "y": 880, + "wires": [ + [ + "222c851d.5d0a3a" + ] + ] + }, + { + "id": "84f3d040.5f7ea", + "type": "ui_button", + "z": "b771c342.49603", + "name": "", + "group": "5517c651.b2f668", + "order": 2, + "width": 5, + "height": 1, + "passthru": false, + "label": "Continue", + "tooltip": "", + "color": "#097479", + "bgcolor": "white", + "icon": "keyboard_tab", + "payload": "{\"tab\":\"Home\"}", + "payloadType": "json", + "topic": "", + "x": 240, + "y": 940, + "wires": [ + [ + "986d960a.c75908" + ] + ] + }, + { + "id": "d027a6bf.7049e8", + "type": "function", + "z": "b771c342.49603", + "name": "get sample_projet", + "func": "msg.payload = msg.payload.sample_project;\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 310, + "y": 40, + "wires": [ + [ + "9c882b37.fde668" + ] + ] + }, + { + "id": "5a811caf.0f3144", + "type": "function", + "z": "b771c342.49603", + "name": "get sample_ship", + "func": "msg.payload = msg.payload.sample_ship;\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 300, + "y": 80, + "wires": [ + [ + "4557d689.a4fa88" + ] + ] + }, + { + "id": "45911c98.2bd83c", + "type": "function", + "z": "b771c342.49603", + "name": "get sample_id", + "func": "msg.payload = msg.payload.sample_id;\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 300, + "y": 120, + "wires": [ + [ + "94eb4221.9b92c" + ] + ] + }, + { + "id": "1e09a4ab.72996b", + "type": "function", + "z": "b771c342.49603", + "name": "get sample_operator", + "func": "msg.payload = msg.payload.sample_operator;\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 320, + "y": 160, + "wires": [ + [ + "82c5fc77.59c97" + ] + ] + }, + { + "id": "a3272681.f271c8", + "type": "function", + "z": "b771c342.49603", + "name": "get sample_sampling_gear", + "func": "msg.topic = \"sample_sampling_gear\"\nif (msg.payload.sample_sampling_gear === undefined){\n msg.payload = \"net\";\n}\nelse\n{\n msg.payload = msg.payload.sample_sampling_gear;\n}\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 340, + "y": 200, + "wires": [ + [ + "fcfc31ae.af3af" + ] + ] + }, + { + "id": "a6907a38.f6611", + "type": "subflow:1c24ad9c.bebec2", + "z": "b771c342.49603", + "name": "", + "env": [], + "x": 70, + "y": 220, + "wires": [ + [ + "d027a6bf.7049e8", + "5a811caf.0f3144", + "45911c98.2bd83c", + "1e09a4ab.72996b", + "8dff1648.82e42", + "9f04c5ec.75f3d8", + "f408a273.4fb538", + "e73fd87d.d24e4", + "489c8e06.cc7d6", + "a3272681.f271c8" + ] + ] + }, + { + "id": "e2b277c1.07283", + "type": "subflow:1c24ad9c.bebec2", + "z": "b771c342.49603", + "name": "", + "env": [], + "x": 690, + "y": 940, + "wires": [ + [] + ] + }, + { + "id": "7116e906.9f50f", + "type": "ui_text", + "z": "b771c342.49603", + "group": "fc5e4e6f.5b1c8", + "order": 1, + "width": 10, + "height": 1, + "name": "GPS Status Display", + "label": "GPS Status:", + "format": "{{msg.payload}}", + "layout": "row-center", + "x": 740, + "y": 1080, + "wires": [] + }, + { + "id": "9c7f7fc9.c8d3a", + "type": "ui_text_input", + "z": "b771c342.49603", + "name": "object_depth_max", + "label": "Max sampling depth (m)", + "tooltip": "in m", + "group": "3e1ba03d.f01d8", + "order": 10, + "width": 5, + "height": 1, + "passthru": true, + "mode": "number", + "delay": "300", + "topic": "object_depth_max", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 650, + "y": 240, + "wires": [ + [ + "9f501f49.45645" + ] + ] + }, + { + "id": "317eeeb7.8d3042", + "type": "ui_text_input", + "z": "b771c342.49603", + "name": "object_depth_min", + "label": "Min sampling depth (m)", + "tooltip": "in m", + "group": "3e1ba03d.f01d8", + "order": 9, + "width": 5, + "height": 1, + "passthru": true, + "mode": "number", + "delay": "300", + "topic": "object_depth_min", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 650, + "y": 280, + "wires": [ + [ + "9f501f49.45645" + ] + ] + }, + { + "id": "cbb123ab.fd3428", + "type": "ui_ui_control", + "z": "b771c342.49603", + "name": "show/hide net groups", + "events": "change", + "x": 1320, + "y": 300, + "wires": [ + [] + ] + }, + { + "id": "642ff403.1ed91c", + "type": "ui_text_input", + "z": "b771c342.49603", + "name": "sample_concentrated_sample_volume", + "label": "Concentrated sample volume (mL)", + "tooltip": "Volume extracted from the net codend (in mL)", + "group": "3e1ba03d.f01d8", + "order": 12, + "width": 10, + "height": 1, + "passthru": true, + "mode": "number", + "delay": "300", + "topic": "sample_concentrated_sample_volume", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 590, + "y": 440, + "wires": [ + [ + "9f501f49.45645" + ] + ] + }, + { + "id": "e967b844.46aa48", + "type": "ui_text_input", + "z": "b771c342.49603", + "name": "sample_gear_net_opening", + "label": "Net opening dimension (mm)", + "tooltip": "Size of the net mouth opening (in mm)", + "group": "cf5d9f0e.d57e7", + "order": 1, + "width": 10, + "height": 1, + "passthru": true, + "mode": "number", + "delay": "300", + "topic": "sample_gear_net_opening", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 620, + "y": 320, + "wires": [ + [ + "9f501f49.45645" + ] + ] + }, + { + "id": "c0ce5626.b6c5", + "type": "ui_toast", + "z": "b771c342.49603", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "topic": "", + "name": "", + "x": 1230, + "y": 620, + "wires": [ + [] + ] + }, + { + "id": "c33f1124.af6688", + "type": "ui_form", + "z": "b771c342.49603", + "name": "sample_location", + "label": "Sample Location", + "group": "cef1e703.bcf3c8", + "order": 1, + "width": 0, + "height": 0, + "options": [ + { + "label": "Latitude (36.574439°N or 36°57.4439'N)", + "value": "object_lat", + "type": "text", + "required": true, + "rows": null + }, + { + "label": "Longitude (110.42100°W or 110°4.2100'W)", + "value": "object_lon", + "type": "text", + "required": true, + "rows": null + }, + { + "label": "Date (YYYY-MM-DD, UTC)", + "value": "object_date", + "type": "text", + "required": true, + "rows": null + }, + { + "label": "Time (HH:MM(:SS), UTC 24h)", + "value": "object_time", + "type": "text", + "required": true, + "rows": null + } + ], + "formValue": { + "object_lat": "", + "object_lon": "", + "object_date": "", + "object_time": "" + }, + "payload": "", + "submit": "Validate", + "cancel": "Reset", + "topic": "sample_location", + "x": 660, + "y": 580, + "wires": [ + [ + "14658615.47c862", + "a9fb1f4b83fc25a7" + ] + ] + }, + { + "id": "358908cd.416ab", + "type": "ui_form", + "z": "b771c342.49603", + "name": "net_throw_location", + "label": "Net Throw Location", + "group": "cf5d9f0e.d57e7", + "order": 3, + "width": 0, + "height": 0, + "options": [ + { + "label": "Latitude (36.574439°N or 36°57.4439'N)", + "value": "object_lat", + "type": "text", + "required": true, + "rows": null + }, + { + "label": "Longitude (110.42100°W or 110°4.2100'W)", + "value": "object_lon", + "type": "text", + "required": true, + "rows": null + }, + { + "label": "Date (YYYY-MM-DD UTC)", + "value": "object_date", + "type": "text", + "required": true, + "rows": null + }, + { + "label": "Time (HH:MM, UTC 24h)", + "value": "object_time", + "type": "text", + "required": true, + "rows": null + } + ], + "formValue": { + "object_lat": "", + "object_lon": "", + "object_date": "", + "object_time": "" + }, + "payload": "", + "submit": "Validate", + "cancel": "", + "topic": "net_throw_location", + "topicType": "str", + "splitLayout": false, + "className": "", + "x": 650, + "y": 620, + "wires": [ + [ + "14658615.47c862", + "ad54b89540460d27" + ] + ] + }, + { + "id": "56d40584.eff4e4", + "type": "ui_form", + "z": "b771c342.49603", + "name": "net_retrieval_location", + "label": "Net Retrieval Location", + "group": "cf5d9f0e.d57e7", + "order": 4, + "width": 0, + "height": 0, + "options": [ + { + "label": "Latitude (36.574439°N or 36°57.4439'N)", + "value": "object_lat_end", + "type": "text", + "required": true, + "rows": null + }, + { + "label": "Longitude (110.42100°W or 110°4.2100'W)", + "value": "object_lon_end", + "type": "text", + "required": true, + "rows": null + }, + { + "label": "Date (YYYY-MM-DD UTC)", + "value": "object_date_end", + "type": "text", + "required": true, + "rows": null + }, + { + "label": "Time (HH:MM, UTC 24h)", + "value": "object_time_end", + "type": "text", + "required": true, + "rows": null + } + ], + "formValue": { + "object_lat_end": "", + "object_lon_end": "", + "object_date_end": "", + "object_time_end": "" + }, + "payload": "", + "submit": "Validate", + "cancel": "", + "topic": "net_retrieval_location", + "topicType": "str", + "splitLayout": false, + "x": 640, + "y": 660, + "wires": [ + [ + "14658615.47c862", + "c21bf0244e67e40a" + ] + ] + }, + { + "id": "14658615.47c862", + "type": "function", + "z": "b771c342.49603", + "name": "Validate Location / Timestamp", + "func": "// Code added here will be run once\n// whenever the node is started.\nfunction ConvertDDMMToDD(input) {\n // Input Format 36°57.4439'N, 110°4.2100'W\n // From https://stackoverflow.com/questions/1140189/converting-latitude-and-longitude-to-decimal-values\n if (!input.match(/\\d+°\\d+\\.*\\d*\\'[NSEW]/)){\n \treturn \"parsing error\"\n }\n var parts = input.split(/[^\\d.\\w]+/)\n if (parts.length != 3){\n \treturn \"parsing error\"\n }\n var dd = Number(parts[0]) + Number(parts[1])/60\n return dd.toFixed(6) + parts[2]\n}\n\nfunction ValidateCoordinates(input, lat){\n // Input Format 36.574439°N, 110.42100°W\n // Or 36°57.4439'N, 110°4.2100'W\n if (input.match(\"'\")){\n input = ConvertDDMMToDD(input)\n }\n \n var error = {}\n\n if (input.startsWith(\"parsing error\")){\n error.topic = \"Error with the \"\n error.payload = \"You need to respect the format example, 36.574439°N or 36°57.4439'N\"\n return [null, error]\n }\n \n var direction = input.match(/[NSEW]/)\n var position = input.match(/[\\+\\-\\d\\.]+/)\n \n if (direction === null){\n error.topic = \"Error with the \"\n error.payload = \"You need to explicitely enter N/S/E/W\"\n return [null, error]\n }\n \n // Test that position is only made of digits!\n if(/^[\\+\\-]/.test(position)){\n error.topic = \"Error with the \"\n error.payload = \"Use of +/- sign is inconsistent with N/S/E/W letter! Please only use N/S/E/W!\"\n return [null, error]\n }\n \n var dd = Number(position)\n if (lat){\n // Check latitude\n if (direction == \"S\" || direction == \"N\") {\n if (dd>90.0){\n error.topic = \"Error with the \"\n error.payload = \"Latitude is more than 90°\"\n return [null, error]\n }\n }\n if (direction == \"W\" || direction == \"E\") {\n error.topic = \"Error with the \"\n error.payload = \"This is not a Latitude!\"\n return [null, error]\n }\n }\n else{\n // Check longitude\n if (direction == \"W\" || direction == \"E\") {\n if (dd>180.0){\n error.topic = \"Error with the \"\n error.payload = \"Longitude is more than 180°\"\n return [null, error]\n }\n }\n if (direction == \"N\" || direction == \"S\") {\n error.topic = \"Error with the \"\n error.payload = \"This is not a Longitude!\"\n return [null, error]\n }\n }\n \n if (direction == \"S\" || direction == \"W\") {\n dd = dd * -1\n } // Don't do anything for N or E\n return [dd.toFixed(4), null]\n \n}\n\nfunction ValidateDate(input){\n // Input Format 2020-12-25\n var error = {};\n \n if (! /20\\d{2}-[0-1]\\d-[0-3]\\d/.test(input)){\n error.topic = \"Error with the date\";\n error.payload = \"The date should respect the ISO format YYYY-MM-DD\";\n return [null, error];\n }\n else {\n var date = input.match(/\\d+/g);\n if (!((2000 < date[0]) && (date[0] < 2100))){\n error.topic = \"Error with the date\"\n error.payload = \"The year should be between 2000 and 2100\"\n return [null, error]\n }\n else if (!((0 < date[1]) && (date[1] <= 12))){\n error.topic = \"Error with the date\"\n error.payload = \"The month should be between 01 and 12\"\n return [null, error]\n }\n else if (!((0 < date[2]) && (date[2] <= 31))){\n error.topic = \"Error with the date\"\n error.payload = \"The day should be between 01 and 31\"\n return [null, error]\n }\n }\n return [input.replace(/-/g, ''), null]\n}\n\nfunction ValidateTime(input){\n // Input Format 12:00\n var error = {}\n \n if (! /[0-2]?\\d:[0-5]\\d/.test(input)){\n error.topic = \"Error with the time\"\n error.payload = \"The date should respect the ISO format HH:MM\"\n return [null, error]\n }\n else {\n var time = input.match(/\\d+/g)\n \n if (!((0 <= time[0]) && (time[0] < 24))){\n error.topic = \"Error with the time\"\n error.payload = \"The hours should be 0 and 23.\"\n return [null, error]\n }\n else if (!((0 <= time[1]) && (time[1] < 60))){\n error.topic = \"Error with the time\"\n error.payload = \"The minutes should be between 0 and 59\"\n return [null, error]\n }\n }\n return [input.replace(/:/g, ''), null]\n}\n\n\nvar ret\nvar payload_for_form = {payload:{}}\nmsg.valid = false\n\nif (msg.topic == \"culture_timestamp\"){\n ret = ValidateDate(msg.payload.object_date)\n if (ret[1] !== null){\n msg.topic = ret[1].topic + \" of the sample\"\n msg.payload = ret[1].payload\n return [msg, null]\n }\n global.set(\"object_date\", ret[0])\n \n ret = ValidateTime(msg.payload.object_time)\n if (ret[1] !== null){\n msg.topic = ret[1].topic + \" of the sample\"\n msg.payload = ret[1].payload\n return [msg, null]\n }\n global.set(\"object_time\", ret[0])\n return [{topic: \"Date and time format valid!\", payload: \"All good!\", valid: true}, payload_for_form]\n}\nelse if (msg.topic == \"net_retrieval_location\"){\n ret = ValidateCoordinates(msg.payload.object_lat_end, true);\n if (ret[1] !== null){\n msg.topic = ret[1].topic + \" Latitude\"\n msg.payload = ret[1].payload\n return [msg, null]\n }\n global.set(\"object_lat_end\", ret[0])\n ret = ValidateCoordinates(msg.payload.object_lon_end, false)\n if (ret[1] !== null){\n msg.topic = ret[1].topic + \" Longitude\"\n msg.payload = ret[1].payload\n return [msg, null]\n }\n global.set(\"object_lon_end\", ret[0]);\n \n ret = ValidateDate(msg.payload.object_date_end)\n if (ret[1] !== null){\n msg.topic = ret[1].topic + \" of the sample retrieval\"\n msg.payload = ret[1].payload\n return [msg, null]\n }\n global.set(\"object_date_end\", ret[0])\n \n ret = ValidateTime(msg.payload.object_time_end)\n if (ret[1] !== null){\n msg.topic = ret[1].topic + \" of the sample retrieval\"\n msg.payload = ret[1].payload\n return [msg, null]\n }\n global.set(\"object_time_end\", ret[0])\n}\nelse{\n ret = ValidateCoordinates(msg.payload.object_lat, true);\n if (ret[1] !== null){\n msg.topic = ret[1].topic + \" Latitude\";\n msg.payload = ret[1].payload\n return [msg, null]\n }\n global.set(\"object_lat\", ret[0]);\n payload_for_form.payload[\"object_lat_end\"] = msg.payload.object_lat;\n \n ret = ValidateCoordinates(msg.payload.object_lon, false);\n if (ret[1] !== null){\n msg.topic = ret[1].topic + \" Longitude\"\n msg.payload = ret[1].payload\n return [msg, null]\n }\n global.set(\"object_lon\", ret[0])\n payload_for_form.payload[\"object_lon_end\"] = msg.payload.object_lon;\n\n ret = ValidateDate(msg.payload.object_date)\n if (ret[1] !== null){\n msg.topic = ret[1].topic + \" of the sample\"\n msg.payload = ret[1].payload\n return [msg, null]\n }\n global.set(\"object_date\", ret[0])\n payload_for_form.payload[\"object_date_end\"] = msg.payload.object_date;\n \n ret = ValidateTime(msg.payload.object_time)\n if (ret[1] !== null){\n msg.topic = ret[1].topic + \" of the sample\"\n msg.payload = ret[1].payload\n return [msg, null]\n }\n global.set(\"object_time\", ret[0])\n payload_for_form.payload[\"object_time_end\"] = msg.payload.object_time;\n}\nreturn [{topic: \"Coordinates valid!\", payload: \"All good!\", valid: true}, payload_for_form]\n", + "outputs": 2, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 930, + "y": 620, + "wires": [ + [ + "c0ce5626.b6c5", + "9a18a4b4.178448" + ], + [ + "56d40584.eff4e4" + ] + ], + "inputLabels": [ + "Location form data" + ], + "outputLabels": [ + "Message", + "Location validated" + ] + }, + { + "id": "46eb1bf8.3dc5f4", + "type": "function", + "z": "b771c342.49603", + "name": "Net check", + "func": "var decknet = {}\nvar activation_msg = {}\n\nif (msg.payload.startsWith(\"net_decknet\")){\n decknet.enabled = true;\n}\nelse {\n decknet.enabled = false;\n}\n\nif (msg.payload.startsWith(\"net\")){\n activation_msg.payload = {\"group\":{\"show\":[\"Sample_Net_Metadata\"],\"hide\":[\"Sample_Sample_Location\",\"Sample_Culture_Date_and_Time\"]}};\n}\nelse if (msg.payload != \"culture\" && msg.payload != \"test\"){\n activation_msg.payload = {\"group\":{\"show\":[\"Sample_Sample_Location\"], \"hide\":[\"Sample_Net_Metadata\",\"Sample_Culture_Date_and_Time\"]}};\n}\n\n\nreturn [decknet, activation_msg];", + "outputs": 2, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 1080, + "y": 240, + "wires": [ + [ + "516375fd.2ed61c", + "470e382a.25691", + "fbe32ac8.ff6a38" + ], + [ + "cbb123ab.fd3428" + ] + ], + "outputLabels": [ + "decknet activation", + "group display control" + ] + }, + { + "id": "516375fd.2ed61c", + "type": "ui_text_input", + "z": "b771c342.49603", + "name": "sample_total_flowmeter_start", + "label": "Decknet flowmeter start", + "tooltip": "in L", + "group": "cf5d9f0e.d57e7", + "order": 6, + "width": 5, + "height": 1, + "passthru": false, + "mode": "text", + "delay": "300", + "topic": "sample_total_flowmeter_start", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 1340, + "y": 220, + "wires": [ + [ + "e9bc112c.eb75f8" + ] + ] + }, + { + "id": "470e382a.25691", + "type": "ui_text_input", + "z": "b771c342.49603", + "name": "sample_total_flowmeter_end", + "label": "Decknet flowmeter end", + "tooltip": "in L", + "group": "cf5d9f0e.d57e7", + "order": 7, + "width": 5, + "height": 1, + "passthru": false, + "mode": "text", + "delay": "300", + "topic": "sample_total_flowmeter_end", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 1340, + "y": 260, + "wires": [ + [ + "e9bc112c.eb75f8" + ] + ] + }, + { + "id": "fbe32ac8.ff6a38", + "type": "ui_template", + "z": "b771c342.49603", + "group": "cf5d9f0e.d57e7", + "name": "Decknet flowmeter read", + "order": 5, + "width": 10, + "height": 1, + "format": "
\n

Decknet flowmeter readings

\n

Those values are used to calculate sample_total_volume. Values are in L.

\n
\n", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "x": 1330, + "y": 180, + "wires": [ + [] + ] + }, + { + "id": "f408a273.4fb538", + "type": "function", + "z": "b771c342.49603", + "name": "get sample_gear_net_opening", + "func": "if (msg.payload.sample_gear_net_opening === null){\n msg.payload = 0;\n global.set(\"sample_gear_net_opening\",msg.payload);\n}\nelse\n{\n msg.payload = msg.payload.sample_gear_net_opening;\n}\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 350, + "y": 320, + "wires": [ + [ + "e967b844.46aa48" + ] + ] + }, + { + "id": "8dff1648.82e42", + "type": "function", + "z": "b771c342.49603", + "name": "get object_depth_max", + "func": "if (msg.payload.object_depth_max === null){\n msg.payload = 0;\n global.set(\"object_depth_max\",msg.payload);\n}\nelse\n{\n msg.payload = msg.payload.object_depth_max;\n}\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 320, + "y": 240, + "wires": [ + [ + "9c7f7fc9.c8d3a" + ] + ] + }, + { + "id": "9f04c5ec.75f3d8", + "type": "function", + "z": "b771c342.49603", + "name": "get object_depth_min", + "func": "if (msg.payload.object_depth_min === null){\n msg.payload = 0;\n global.set(\"object_depth_min\",msg.payload);\n}\nelse\n{\n msg.payload = msg.payload.object_depth_min;\n}\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 320, + "y": 280, + "wires": [ + [ + "317eeeb7.8d3042" + ] + ] + }, + { + "id": "9a18a4b4.178448", + "type": "function", + "z": "b771c342.49603", + "name": "calculate sample_total_volume", + "func": "\n/*object_lat = 33.95 \nobject_lon = 118.4 \nobject_lat_end = 40.6333 \nobject_lon_end = 73.78333\nsample_gear_net_opening = 40*/\n\n// Copyright 1997 Ed Williams. All rights reserved\n// Adapted by Romain Bazile - Ocean Trotter - 01-2021\n\ndecpl=4 // Dec places of minutes output\n\nellipse = {\"name\":\"WSG84\", \"a\":6378.137/1.852, \"invf\":298.257223563}\n\nfunction ComputeDistance(lat1, lon1, lat2, lon2){\n var d,crs12,crs21\n var argacos\n var a,invf\n \n // lat and lon in radian\n lat1=(Math.PI/180)*lat1\n lat2=(Math.PI/180)*lat2\n lon1=(Math.PI/180)*lon1\n lon2=(Math.PI/180)*lon2\n \n //alert(\"lat1=\" + lat1 + \"lon1=\" + lon1 +\"\\nlat2=\" +lat2+ \"lon2=\"+lon2)\n \n /* get distance conversion factor */\n dc=1.852 //km\n //alert(\"dc=\" +dc)\n \n //showProps(ellipse,\"ellipse\")\n \n // elliptic code\n d=crsdist_ell(lat1,-lon1,lat2,-lon2,ellipse) // ellipse uses East negative\n d=d*dc // go to physical units\n \n //alert(\"d=\"+d+\" crs12=\"+crs12+\" crs21=\"+crs21)\n return d\n}\n\nfunction crsdist(lat1,lon1,lat2,lon2){ // radian args\n /* compute course and distance (spherical) */\n if ((lat1+lat2===0) && (Math.abs(lon1-lon2)==Math.PI) && \n (Math.abs(lat1) != (Math.PI/180)*90)){\t\n \talert(\"Course between antipodal points is undefined\")\n }\n \n d = Math.acos(Math.sin(lat1)*Math.sin(lat2)+Math.cos(lat1)*Math.cos(lat2)*Math.cos(lon1-lon2))\n return d\n}\n\nfunction crsdist_ell(glat1,glon1,glat2,glon2,ellipse){\n // glat1 initial geodetic latitude in radians N positive \n // glon1 initial geodetic longitude in radians E positive \n // glat2 final geodetic latitude in radians N positive \n // glon2 final geodetic longitude in radians E positive \n a=ellipse.a\n f=1/ellipse.invf\n //alert(\"a=\"+a+\" f=\"+f)\n var r, tu1, tu2, cu1, su1, cu2, s1, b1, f1\n var x, sx, cx, sy, cy,y, sa, c2a, cz, e, c, d\n var EPS= 0.00000000005\n var faz, baz, s\n var iter=1\n var MAXITER=100\n if ((glat1+glat2===0) && (Math.abs(glon1-glon2)==Math.PI)){\n alert(\"Course and distance between antipodal points is undefined\")\n glat1=glat1+0.00001 // allow algorithm to complete\n }\n if (glat1==glat2 && (glon1==glon2 || Math.abs(Math.abs(glon1-glon2)-2*Math.PI) < EPS)){\n alert(\"Points 1 and 2 are identical- course undefined\")\n out=new MakeArray(0)\n out.d=0\n out.crs12=0\n out.crs21=Math.PI\n return out\n }\n r = 1 - f\n tu1 = r * Math.tan (glat1)\n tu2 = r * Math.tan (glat2)\n cu1 = 1 / Math.sqrt (1 + tu1 * tu1)\n su1 = cu1 * tu1\n cu2 = 1 / Math.sqrt (1 + tu2 * tu2)\n s1 = cu1 * cu2\n b1 = s1 * tu2\n f1 = b1 * tu1\n x = glon2 - glon1\n d = x + 1 // force one pass\n while ((Math.abs(d - x) > EPS) && (iter < MAXITER))\n {\n iter=iter+1\n sx = Math.sin (x)\n // alert(\"sx=\"+sx)\n cx = Math.cos (x)\n tu1 = cu2 * sx\n tu2 = b1 - su1 * cu2 * cx\n sy = Math.sqrt(tu1 * tu1 + tu2 * tu2)\n cy = s1 * cx + f1\n y = atan2 (sy, cy)\n sa = s1 * sx / sy\n c2a = 1 - sa * sa\n cz = f1 + f1\n if (c2a > 0)\n cz = cy - cz / c2a\n e = cz * cz * 2 - 1\n c = ((-3 * c2a + 4) * f + 4) * c2a * f / 16\n d = x\n x = ((e * cy * c + cz) * sy * c + y) * sa\n x = (1 - c) * x * f + glon2 - glon1\n }\n x = Math.sqrt ((1 / (r * r) - 1) * c2a + 1)\n x +=1\n x = (x - 2) / x\n c = 1 - x\n c = (x * x / 4 + 1) / c\n d = (0.375 * x * x - 1) * x\n x = e * cy\n d = ((((sy*sy*4-3)*(1-e-e)*cz*d/6-x)*d/4+cz)*sy*d+y)*c*a*r\n if (Math.abs(iter-MAXITER)0) && (y>=0)){ out= Math.atan(y/x)}\n if ((x >0) && (y<0)) { out= Math.atan(y/x)+2*Math.PI}\n if ((x===0) && (y>0)) { out= Math.PI/2}\n if ((x===0) && (y<0)) { out= 3*Math.PI/2} \n if ((x===0) && (y===0)) {\n alert(\"atan2(0,0) undefined\")\n out= 0\n } \n return out\n}\n\nfunction showProps(obj,objName){\n var result=\"\"\n for (var i in obj){\n result +=objName + \".\" + i + \" = \" + obj[i] + \"\\n\"\n }\n alert(result)\n}\n\n\nif (msg.valid){\n msg.topic=\"sample_total_volume\"\n \n var object_lat_end = global.get(\"object_lat_end\")\n var object_lon_end = global.get(\"object_lon_end\")\n var sample_sampling_gear = global.get(\"sample_sampling_gear\")\n \n if (sample_sampling_gear.startsWith(\"net\") && sample_sampling_gear != \"net_decknet\") {\n if (!(isNaN(object_lat_end) && isNaN(object_lon_end))){\n var object_lat = global.get(\"object_lat\")\n var object_lon = global.get(\"object_lon\")\n var sample_gear_net_opening = global.get(\"sample_gear_net_opening\");\n\n distance_km = ComputeDistance(object_lat, object_lon, object_lat_end, object_lon_end)\n\n sample_total_volume = distance_km*(Math.PI*(sample_gear_net_opening/2)*(sample_gear_net_opening/2)) // liters\n sample_total_volume = Math.round(sample_total_volume + Number.EPSILON)\n msg.payload = sample_total_volume\n return msg\n }\n }\n}", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 930, + "y": 760, + "wires": [ + [ + "4f6afc5a.81e454" + ] + ] + }, + { + "id": "4fb4e0ad.c417c", + "type": "ui_text", + "z": "b771c342.49603", + "group": "fc5e4e6f.5b1c8", + "order": 6, + "width": 5, + "height": 1, + "name": "Latitude", + "label": "Latitude", + "format": "{{msg.payload.lat.deg}}°{{msg.payload.lat.min}}'{{msg.payload.lat.sec}}{{msg.payload.lat.dir}}", + "layout": "col-center", + "x": 700, + "y": 1120, + "wires": [] + }, + { + "id": "8d2b5026.13e6e8", + "type": "ui_text", + "z": "b771c342.49603", + "group": "fc5e4e6f.5b1c8", + "order": 7, + "width": 5, + "height": 1, + "name": "Longitude", + "label": "Longitude", + "format": "{{msg.payload.lon.deg}}°{{msg.payload.lon.min}}'{{msg.payload.lon.sec}}{{msg.payload.lon.dir}}", + "layout": "col-center", + "x": 700, + "y": 1160, + "wires": [] + }, + { + "id": "258b4562.9f778a", + "type": "function", + "z": "b771c342.49603", + "name": "Convert DD to DMS", + "func": "function ConvertDDToDMS(D, lng){\n // from https://stackoverflow.com/a/5786281/2108279\n return {\n dir : D<0?lng?'W':'S':lng?'E':'N',\n deg : 0|(D<0?D=-D:D),\n min : 0|D%1*60,\n sec :(0|D*60%1*6000)/100\n };\n}\n\nmsg.payload = {\n \"lat\":ConvertDDToDMS(msg.payload.lat, false),\n \"lon\":ConvertDDToDMS(msg.payload.lon, true)\n};\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 490, + "y": 1140, + "wires": [ + [ + "4fb4e0ad.c417c", + "8d2b5026.13e6e8" + ] + ] + }, + { + "id": "7c4ce5f3.62dd5c", + "type": "ui_text", + "z": "b771c342.49603", + "group": "fc5e4e6f.5b1c8", + "order": 4, + "width": 2, + "height": 1, + "name": "Speed", + "label": "Speed", + "format": "{{msg.payload}} kts", + "layout": "col-center", + "x": 690, + "y": 1200, + "wires": [] + }, + { + "id": "54e37580.fdc31c", + "type": "ui_text", + "z": "b771c342.49603", + "group": "fc5e4e6f.5b1c8", + "order": 5, + "width": 2, + "height": 1, + "name": "Direction", + "label": "Direction", + "format": "{{msg.payload.track}} °", + "layout": "col-center", + "x": 700, + "y": 1240, + "wires": [] + }, + { + "id": "cc21ca16.b92928", + "type": "function", + "z": "b771c342.49603", + "name": "GPS Mode", + "func": "switch (msg.payload.mode){\n case 1:msg.payload = \"No Fix\"; break\n case 2:msg.payload = \"2D Fix\"; break\n case 3:msg.payload = \"3D Fix\"; break\n default: msg.payload = \"No info\"\n}\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 470, + "y": 1080, + "wires": [ + [ + "7116e906.9f50f" + ] + ] + }, + { + "id": "4a4de52c.cf2884", + "type": "function", + "z": "b771c342.49603", + "name": "Speed conversion", + "func": "msg.payload = (0|msg.payload.speed) * 1.9438\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 490, + "y": 1200, + "wires": [ + [ + "7c4ce5f3.62dd5c" + ] + ] + }, + { + "id": "35ad311f.344c76", + "type": "ui_text", + "z": "b771c342.49603", + "group": "fc5e4e6f.5b1c8", + "order": 2, + "width": 5, + "height": 1, + "name": "Time", + "label": "Time", + "format": "{{msg.payload.time}}", + "layout": "col-center", + "x": 690, + "y": 1280, + "wires": [] + }, + { + "id": "e73fd87d.d24e4", + "type": "function", + "z": "b771c342.49603", + "name": "get acq_minimum_mesh", + "func": "msg.payload = msg.payload.acq_minimum_mesh;\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 330, + "y": 360, + "wires": [ + [ + "1aad56b31b5647ce" + ] + ] + }, + { + "id": "489c8e06.cc7d6", + "type": "function", + "z": "b771c342.49603", + "name": "get acq_maximum_mesh", + "func": "msg.payload = msg.payload.acq_maximum_mesh;\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 330, + "y": 400, + "wires": [ + [ + "10eb31a2d7a6590c" + ] + ] + }, + { + "id": "73c4a14a.9b93c8", + "type": "function", + "z": "b771c342.49603", + "name": "Convert time", + "func": "msg.payload.time = msg.payload.time.replace('T', ' ')\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 470, + "y": 1280, + "wires": [ + [ + "35ad311f.344c76" + ] + ] + }, + { + "id": "58de1340.3cc354", + "type": "ui_text_input", + "z": "b771c342.49603", + "name": "sample_dilution_factor", + "label": "Dilution Factor", + "tooltip": "0.5 if diluted by two; 2 if concentrated by a factor 2", + "group": "3e1ba03d.f01d8", + "order": 13, + "width": 10, + "height": 1, + "passthru": true, + "mode": "number", + "delay": "300", + "topic": "sample_dilution_factor", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 640, + "y": 480, + "wires": [ + [ + "9f501f49.45645" + ] + ] + }, + { + "id": "4f6afc5a.81e454", + "type": "ui_text_input", + "z": "b771c342.49603", + "name": "sample_total_volume", + "label": "Filtered volume (in L)", + "tooltip": "Calculated or hand filled", + "group": "3e1ba03d.f01d8", + "order": 11, + "width": 0, + "height": 0, + "passthru": true, + "mode": "text", + "delay": "300", + "topic": "sample_total_volume", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 1220, + "y": 760, + "wires": [ + [ + "e1f2f6eb.fe1dd" + ] + ] + }, + { + "id": "e1f2f6eb.fe1dd", + "type": "function", + "z": "b771c342.49603", + "name": "set global", + "func": "global.set(msg.topic,msg.payload);", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 1420, + "y": 760, + "wires": [ + [] + ] + }, + { + "id": "e9bc112c.eb75f8", + "type": "function", + "z": "b771c342.49603", + "name": "Calculate volume", + "func": "if (msg.topic == \"sample_total_flowmeter_start\"){\n context.set(\"sample_total_flowmeter_start\", msg.payload);\n}\nif (msg.topic == \"sample_total_flowmeter_end\"){\n context.set(\"sample_total_flowmeter_end\", msg.payload);\n}\n\nif (context.keys().length == 2){\n sample_total_volume = context.get(\"sample_total_flowmeter_end\") - context.get(\"sample_total_flowmeter_start\");\n msg.topic=\"sample_total_volume\"\n msg.payload=sample_total_volume\n return msg\n}\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 1610, + "y": 240, + "wires": [ + [ + "4f6afc5a.81e454" + ] + ] + }, + { + "id": "cdd4181922eecf11", + "type": "ui_text_input", + "z": "b771c342.49603", + "name": "sample_speed_through_water", + "label": "Speed Through Water (kts)", + "tooltip": "in knots", + "group": "cf5d9f0e.d57e7", + "order": 2, + "width": 10, + "height": 1, + "passthru": true, + "mode": "number", + "delay": "300", + "topic": "sample_speed_through_water", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 610, + "y": 520, + "wires": [ + [ + "9f501f49.45645" + ] + ] + }, + { + "id": "1aad56b31b5647ce", + "type": "ui_text_input", + "z": "b771c342.49603", + "name": "acq_minimum_mesh", + "label": "Minimal fraction size (μm)", + "tooltip": "Net mesh pore size or minimal filtration mesh pore size", + "group": "3e1ba03d.f01d8", + "order": 7, + "width": 5, + "height": 1, + "passthru": true, + "mode": "number", + "delay": "300", + "topic": "acq_minimum_mesh", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 640, + "y": 360, + "wires": [ + [ + "9f501f49.45645" + ] + ] + }, + { + "id": "10eb31a2d7a6590c", + "type": "ui_text_input", + "z": "b771c342.49603", + "name": "acq_maximum_mesh", + "label": "Maximal fraction size (μm)", + "tooltip": "Maximal filtration mesh pore size", + "group": "3e1ba03d.f01d8", + "order": 8, + "width": 5, + "height": 1, + "passthru": true, + "mode": "number", + "delay": "300", + "topic": "acq_maximum_mesh", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 640, + "y": 400, + "wires": [ + [ + "9f501f49.45645" + ] + ] + }, + { + "id": "3ac7b631f5d8ef90", + "type": "function", + "z": "b771c342.49603", + "name": "Culture check", + "func": "var activation_msg = {}\nvar date_msg = {}\nvar timestamp=new Date().toISOString();\n\nif (msg.payload === \"culture\"){\n activation_msg.payload = {\"group\":{\"show\":[\"Sample_Culture_Date_and_Time\"],\"hide\":[\"Sample_Sample_Location\", \"Sample_Net_Metadata\"]}};\n global.set(\"object_lat\", \"-90.0000\")\n global.set(\"object_lon\", \"0.0000\")\n date_msg.payload = {\"object_date\": timestamp.split('T')[0],\n \"object_time\": timestamp.split('T')[1].split('.')[0]}\n return [activation_msg, date_msg];\n}\nelse if (msg.payload === \"test\"){\n activation_msg.payload = {\"group\":{\"hide\":[\"Sample_Culture_Date_and_Time\", \"Sample_Sample_Location\", \"Sample_Net_Metadata\"]}};\n global.set(\"object_lat\", \"-90.0000\")\n global.set(\"object_lon\", \"0.0000\")\n global.set(\"object_date\", timestamp.split('T')[0])\n global.set(\"object_time\", timestamp.split('T')[1].split('.')[0])\n return [activation_msg, null];\n}\nelse{\n return [null, null]\n}\n\n", + "outputs": 2, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 1100, + "y": 320, + "wires": [ + [ + "cbb123ab.fd3428" + ], + [ + "05c6aff2afbd69cf" + ] + ], + "outputLabels": [ + "decknet activation", + "" + ] + }, + { + "id": "05c6aff2afbd69cf", + "type": "ui_form", + "z": "b771c342.49603", + "name": "culture_timestamp", + "label": "Culture timestamp", + "group": "7bc0a4c416e4545c", + "order": 1, + "width": 0, + "height": 0, + "options": [ + { + "label": "Date (YYYY-MM-DD, UTC)", + "value": "object_date", + "type": "text", + "required": true, + "rows": null + }, + { + "label": "Time (HH:MM(:SS), UTC 24h)", + "value": "object_time", + "type": "text", + "required": true, + "rows": null + } + ], + "formValue": { + "object_date": "", + "object_time": "" + }, + "payload": "", + "submit": "Validate", + "cancel": "Reset", + "topic": "culture_timestamp", + "topicType": "str", + "splitLayout": false, + "className": "", + "x": 650, + "y": 700, + "wires": [ + [ + "14658615.47c862", + "f8044c35996322e6" + ] + ] + }, + { + "id": "a9fb1f4b83fc25a7", + "type": "change", + "z": "b771c342.49603", + "name": "Repopulate input fields", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "payload", + "tot": "msg" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 400, + "y": 580, + "wires": [ + [ + "c33f1124.af6688" + ] + ] + }, + { + "id": "ad54b89540460d27", + "type": "change", + "z": "b771c342.49603", + "name": "Repopulate input fields", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "payload", + "tot": "msg" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 400, + "y": 620, + "wires": [ + [ + "358908cd.416ab" + ] + ] + }, + { + "id": "c21bf0244e67e40a", + "type": "change", + "z": "b771c342.49603", + "name": "Repopulate input fields", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "payload", + "tot": "msg" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 400, + "y": 660, + "wires": [ + [ + "56d40584.eff4e4" + ] + ] + }, + { + "id": "f8044c35996322e6", + "type": "change", + "z": "b771c342.49603", + "name": "Repopulate input fields", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "payload", + "tot": "msg" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 400, + "y": 700, + "wires": [ + [ + "05c6aff2afbd69cf" + ] + ] + }, + { + "id": "6a84252a.d52a0c", + "type": "ui_template", + "z": "bccd1f23.87219", + "group": "833bc5bb.217ba8", + "name": "Stream Pi Camera", + "order": 1, + "width": 18, + "height": 14, + "format": "
\n \"If\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 610, + "y": 40, + "wires": [ + [] + ] + }, + { + "id": "dc48dc42.98d18", + "type": "function", + "z": "bccd1f23.87219", + "name": "set global", + "func": "global.set(msg.topic,msg.payload);", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 880, + "y": 440, + "wires": [ + [] + ] + }, + { + "id": "811cd88c.daf528", + "type": "ui_button", + "z": "bccd1f23.87219", + "name": "down", + "group": "fbd92986.1028c8", + "order": 8, + "width": 4, + "height": 1, + "passthru": true, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "", + "icon": "fa-angle-double-down fa-3x", + "payload": "DOWN", + "payloadType": "str", + "topic": "actuator/focus", + "x": 550, + "y": 800, + "wires": [ + [ + "65ad39d.b6d4d48" + ] + ] + }, + { + "id": "edda4df4.76de2", + "type": "ui_button", + "z": "bccd1f23.87219", + "name": "up", + "group": "fbd92986.1028c8", + "order": 1, + "width": 4, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "", + "icon": "fa-angle-double-up fa-3x", + "payload": "UP", + "payloadType": "str", + "topic": "actuator/focus", + "x": 550, + "y": 760, + "wires": [ + [ + "65ad39d.b6d4d48" + ] + ] + }, + { + "id": "68962547.34a67c", + "type": "ui_text_input", + "z": "bccd1f23.87219", + "name": "pump_manual_volume", + "label": "Volume to pass (ml)", + "tooltip": "Tiny values are accepted down to 0.001mL", + "group": "707d9797.c8e798", + "order": 3, + "width": 2, + "height": 1, + "passthru": true, + "mode": "text", + "delay": "300", + "topic": "pump_manual_volume", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 600, + "y": 420, + "wires": [ + [ + "dc48dc42.98d18" + ] + ] + }, + { + "id": "6c792043.b6ff9", + "type": "ui_ui_control", + "z": "bccd1f23.87219", + "name": "", + "events": "change", + "x": 560, + "y": 1140, + "wires": [ + [] + ] + }, + { + "id": "902429eb.ceacb8", + "type": "ui_toast", + "z": "bccd1f23.87219", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "topic": "", + "name": "", + "x": 570, + "y": 1220, + "wires": [ + [] + ] + }, + { + "id": "fe840e05.b46f3", + "type": "function", + "z": "bccd1f23.87219", + "name": "Check form", + "func": "var acq_fnumber_objective= global.get(\"acq_fnumber_objective\");\n\nif (acq_fnumber_objective === undefined || acq_fnumber_objective === \"\") {\n msg.topic = \"Missing entry :\";\n msg.payload = \"Focal Length of the objective\";\n return [null, msg];\n}\n\nmsg.topic = \"Change Tab\";\nmsg.payload={\"tab\":\"Fluidic Acquisition\"};\nreturn [msg, null];", + "outputs": 2, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 330, + "y": 1180, + "wires": [ + [ + "6c792043.b6ff9", + "326a1d95.ca21aa" + ], + [ + "902429eb.ceacb8" + ] + ], + "outputLabels": [ + "message", + "error" + ] + }, + { + "id": "5846b1d4.7971b", + "type": "ui_button", + "z": "bccd1f23.87219", + "name": "Backward", + "group": "707d9797.c8e798", + "order": 2, + "width": 1, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "", + "icon": "fa-rotate-left fa-2x", + "payload": "BACKWARD", + "payloadType": "str", + "topic": "actuator/pump", + "x": 560, + "y": 280, + "wires": [ + [ + "3cb96380.e575ec" + ] + ] + }, + { + "id": "2cab680b.baf888", + "type": "ui_button", + "z": "bccd1f23.87219", + "name": "Forward", + "group": "707d9797.c8e798", + "order": 4, + "width": 1, + "height": 1, + "passthru": true, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "", + "icon": "fa-rotate-right fa-2x", + "payload": "FORWARD", + "payloadType": "str", + "topic": "actuator/pump", + "x": 560, + "y": 320, + "wires": [ + [ + "3cb96380.e575ec" + ] + ] + }, + { + "id": "9b515beb.4aea48", + "type": "ui_template", + "z": "bccd1f23.87219", + "group": "4248342d.e55fac", + "name": "Magnification", + "order": 4, + "width": 0, + "height": 0, + "format": "
\n Magnification : X\n \n \n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": false, + "templateScope": "local", + "x": 1340, + "y": 80, + "wires": [ + [] + ] + }, + { + "id": "8038414a.34461", + "type": "function", + "z": "bccd1f23.87219", + "name": "Calculate optics", + "func": "var acq_fnumber_objective = String(global.get(\"acq_fnumber_objective\"));\nvar acq_camera = global.get(\"acq_camera\")\n\n// Those values needs to be recalculated, they are not good!\nif (acq_camera == \"HQ Camera\"){\n switch(acq_fnumber_objective) {\n case \"25\":\n acq_magnification= 0.6;\n process_pixel= 1.56;\n sug_min= 60;\n sug_max= 670;\n sug_flowrate= 3;\n break;\n case \"16\":\n acq_magnification= 1.6;\n process_pixel= 1.01;\n sug_min= 40;\n sug_max= 430;\n sug_flowrate= 2.4;\n break;\n case \"12\":\n acq_magnification= 1.20;\n process_pixel= 0.79;\n sug_min= 30;\n sug_max= 340;\n sug_flowrate= 1.25;\n break;\n case \"8\":\n acq_magnification= 1.78;\n process_pixel= 0.53;\n sug_min= 20;\n sug_max= 230;\n sug_flowrate= 0.42;\n break;\n case \"6\":\n acq_magnification= 2.36;\n process_pixel= 0.41;\n sug_min= 15;\n sug_max= 170;\n sug_flowrate= 0.32;\n break;\n }\n}\nelse if (acq_camera == \"Camera v2.1\"){\n switch(acq_fnumber_objective) {\n case \"25\":\n acq_magnification= 0.6;\n process_pixel= 1.86;\n sug_min= 60;\n sug_max= 670;\n sug_flowrate= 3;\n break;\n case \"16\":\n acq_magnification= 1.6;\n process_pixel= 0.7;\n sug_min= 40;\n sug_max= 430;\n sug_flowrate= 2.4;\n break;\n case \"12\":\n acq_magnification= 1.20;\n process_pixel= 0.94;\n sug_min= 30;\n sug_max= 340;\n sug_flowrate= 1.25;\n break;\n case \"8\":\n acq_magnification= 1.78;\n process_pixel= 0.63;\n sug_min= 20;\n sug_max= 230;\n sug_flowrate= 0.42;\n break;\n case \"6\":\n acq_magnification= 2.36;\n process_pixel= 0.48;\n sug_min= 15;\n sug_max= 170;\n sug_flowrate= 0.32;\n break;\n }\n}else {\n acq_magnification= \"ERROR\";\n process_pixel= \"ERROR\";\n sug_min= \"ERROR\";\n sug_max= \"ERROR\";\n sug_flowrate= \"ERROR\";\n}\n\nvar process_pixel_fixed = global.get(\"process_pixel_fixed\")\n\nif (process_pixel_fixed !== undefined && process_pixel_fixed !== \"\") {\n process_pixel = process_pixel_fixed\n}\n\nglobal.set(\"process_pixel\",process_pixel);\n\nglobal.set(\"acq_magnification\",acq_magnification);\n\n\nreturn [{payload: acq_fnumber_objective}, {payload: acq_magnification}, {payload: process_pixel}, {payload: sug_min}, {payload: sug_max}];", + "outputs": 5, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 1080, + "y": 120, + "wires": [ + [ + "335a730b9a3830ff" + ], + [ + "9b515beb.4aea48" + ], + [ + "3d2360ad.e41e7" + ], + [ + "8e66977b.9166a8" + ], + [ + "26b32f2c.c64fc" + ] + ], + "inputLabels": [ + "acq_fnumber_objective" + ], + "outputLabels": [ + "acq_magnification", + "process_pixel", + "sug_min", + "sug_max", + "" + ] + }, + { + "id": "3d2360ad.e41e7", + "type": "ui_template", + "z": "bccd1f23.87219", + "group": "4248342d.e55fac", + "name": "process_pixel", + "order": 5, + "width": 0, + "height": 0, + "format": "
\n Pixel resolution :\n \n μm\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": false, + "templateScope": "local", + "x": 1340, + "y": 120, + "wires": [ + [] + ] + }, + { + "id": "8e66977b.9166a8", + "type": "ui_template", + "z": "bccd1f23.87219", + "group": "4248342d.e55fac", + "name": "min_size", + "order": 6, + "width": 0, + "height": 0, + "format": "
\n Smallest cells to explore :\n \n μm\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "templateScope": "local", + "x": 1320, + "y": 160, + "wires": [ + [] + ] + }, + { + "id": "26b32f2c.c64fc", + "type": "ui_template", + "z": "bccd1f23.87219", + "group": "4248342d.e55fac", + "name": "max_size", + "order": 7, + "width": 0, + "height": 0, + "format": "
\n Biggest cells to explore :\n \n μm\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "templateScope": "local", + "x": 1320, + "y": 200, + "wires": [ + [] + ] + }, + { + "id": "f61aaed5.1e64", + "type": "ui_button", + "z": "bccd1f23.87219", + "name": "", + "group": "7a0b4877.a5d268", + "order": 1, + "width": 2, + "height": 1, + "passthru": false, + "label": "Previous", + "tooltip": "", + "color": "#097479", + "bgcolor": "white", + "icon": "keyboard_return", + "payload": "{\"tab\":\"Sample\"}", + "payloadType": "json", + "topic": "", + "x": 140, + "y": 1140, + "wires": [ + [ + "6c792043.b6ff9" + ] + ] + }, + { + "id": "9ba6ec0a.22c96", + "type": "ui_button", + "z": "bccd1f23.87219", + "name": "", + "group": "7a0b4877.a5d268", + "order": 2, + "width": 2, + "height": 1, + "passthru": false, + "label": "Continue", + "tooltip": "", + "color": "#097479", + "bgcolor": "white", + "icon": "keyboard_tab", + "payload": "{\"tab\":\"Home\"}", + "payloadType": "json", + "topic": "", + "x": 140, + "y": 1180, + "wires": [ + [ + "fe840e05.b46f3" + ] + ] + }, + { + "id": "3cb96380.e575ec", + "type": "function", + "z": "bccd1f23.87219", + "name": "pump", + "func": "var manual_volume= global.get(\"pump_manual_volume\");\nvar flowrate= global.get(\"pump_flowrate\");\n\nif (manual_volume === undefined || manual_volume === \"\" || manual_volume === null) {\n msg.topic = \"Missing entry :\"\n msg.payload = \"Volume to pass\";\n return [null, msg];\n}\nelse if (flowrate === undefined || flowrate === \"\" || flowrate === null) {\n msg.topic = \"Missing entry :\"\n msg.payload = \"Flowrate\";\n return [null, msg];\n}\nelse {\n msg.topic = \"actuator/pump\";\n // msg.payload is FORWARD or BACKWARD here\n msg.payload={\"action\":\"move\", \n \"direction\":msg.payload,\n \"volume\":manual_volume,\n \"flowrate\":flowrate};\n}\nreturn [msg, null];", + "outputs": 2, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 750, + "y": 300, + "wires": [ + [ + "bdc8ce57.de1f08" + ], + [ + "8bcce348.efc1a" + ] + ], + "inputLabels": [ + "direction" + ], + "outputLabels": [ + "message", + "error" + ] + }, + { + "id": "8bcce348.efc1a", + "type": "ui_toast", + "z": "bccd1f23.87219", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "topic": "", + "name": "", + "x": 1090, + "y": 300, + "wires": [ + [] + ] + }, + { + "id": "bdc8ce57.de1f08", + "type": "mqtt out", + "z": "bccd1f23.87219", + "name": "", + "topic": "", + "qos": "", + "retain": "", + "broker": "8dc3722c.06efa8", + "x": 1210, + "y": 260, + "wires": [] + }, + { + "id": "d71d224f.0585d8", + "type": "ui_toast", + "z": "bccd1f23.87219", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "topic": "", + "name": "", + "x": 1090, + "y": 800, + "wires": [ + [] + ] + }, + { + "id": "65ad39d.b6d4d48", + "type": "function", + "z": "bccd1f23.87219", + "name": "focus", + "func": "var distance = global.get(\"focus_distance\");\nvar speed = global.get(\"focus_speed\");\n\nif (distance === undefined || distance === \"\" || distance === null) {\n msg.topic = \"Missing entry :\"\n msg.payload = \"Distance\";\n return [null, msg]\n}\nif (speed === undefined || speed === \"\" || speed === null) {\n msg.topic = \"Missing entry :\"\n msg.payload = \"Speed\";\n return [null, msg]\n}\n// msg.payload is UP or DOWN here\nmsg.payload={\"action\":\"move\", \n \"direction\":msg.payload,\n \"distance\":(distance/1000),\n \"speed\": (speed/1000)\n};\nreturn [msg, null];", + "outputs": 2, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 850, + "y": 780, + "wires": [ + [ + "62030521.88317c" + ], + [ + "d71d224f.0585d8" + ] + ], + "inputLabels": [ + "direction" + ], + "outputLabels": [ + "message", + "error" + ] + }, + { + "id": "1962d999.4a97e6", + "type": "ui_button", + "z": "bccd1f23.87219", + "name": "stop focus", + "group": "fbd92986.1028c8", + "order": 9, + "width": 0, + "height": 0, + "passthru": true, + "label": " STOP FOCUS", + "tooltip": "", + "color": "", + "bgcolor": "#AD1625", + "icon": "fa-pause fa-2x", + "payload": "{\"action\":\"stop\"}", + "payloadType": "json", + "topic": "actuator/focus", + "x": 570, + "y": 560, + "wires": [ + [ + "62030521.88317c" + ] + ] + }, + { + "id": "62030521.88317c", + "type": "mqtt out", + "z": "bccd1f23.87219", + "name": "", + "topic": "", + "qos": "", + "retain": "", + "broker": "8dc3722c.06efa8", + "x": 1210, + "y": 720, + "wires": [] + }, + { + "id": "3bd43039.bc5fb8", + "type": "ui_button", + "z": "bccd1f23.87219", + "name": "", + "group": "fbd92986.1028c8", + "order": 2, + "width": 4, + "height": 1, + "passthru": false, + "label": "UP 1mm", + "tooltip": "", + "color": "", + "bgcolor": "", + "icon": "fa-angle-up fa-3x", + "payload": "{\"action\":\"move\",\"direction\":\"UP\",\"distance\":1}", + "payloadType": "json", + "topic": "actuator/focus", + "topicType": "str", + "x": 560, + "y": 600, + "wires": [ + [ + "62030521.88317c" + ] + ] + }, + { + "id": "c0663029.2d03b", + "type": "ui_button", + "z": "bccd1f23.87219", + "name": "", + "group": "fbd92986.1028c8", + "order": 7, + "width": 4, + "height": 1, + "passthru": false, + "label": "DOWN 1mm", + "tooltip": "", + "color": "", + "bgcolor": "", + "icon": "fa-angle-down fa-3x", + "payload": "{\"action\":\"move\",\"direction\":\"DOWN\",\"distance\":1}", + "payloadType": "json", + "topic": "actuator/focus", + "topicType": "str", + "x": 570, + "y": 720, + "wires": [ + [ + "62030521.88317c" + ] + ] + }, + { + "id": "71f55a58.d7eaf4", + "type": "inject", + "z": "bccd1f23.87219", + "name": "Default: 500µm", + "props": [ + { + "p": "payload" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "0.5", + "topic": "", + "payload": "500", + "payloadType": "num", + "x": 120, + "y": 460, + "wires": [ + [ + "be33e564.029358" + ] + ] + }, + { + "id": "9a1d0e7c.2d5a1", + "type": "inject", + "z": "bccd1f23.87219", + "name": "Default: OFF", + "props": [ + { + "p": "payload" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": 0.1, + "topic": "", + "payload": "off", + "payloadType": "str", + "x": 130, + "y": 120, + "wires": [ + [ + "f0775525.cf806" + ] + ] + }, + { + "id": "f782a471.447748", + "type": "inject", + "z": "bccd1f23.87219", + "name": "Default: 2mL/min", + "props": [ + { + "p": "payload" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "0.5", + "topic": "", + "payload": "2", + "payloadType": "num", + "x": 130, + "y": 380, + "wires": [ + [ + "cb2d5174.cfe9f" + ] + ] + }, + { + "id": "73b8252a.5ca754", + "type": "inject", + "z": "bccd1f23.87219", + "name": "Default: 2mL", + "props": [ + { + "p": "payload" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "0.5", + "topic": "", + "payload": "2", + "payloadType": "num", + "x": 110, + "y": 420, + "wires": [ + [ + "68962547.34a67c" + ] + ] + }, + { + "id": "6451f991.aaac1", + "type": "ui_button", + "z": "bccd1f23.87219", + "name": "stop pump", + "group": "707d9797.c8e798", + "order": 5, + "width": 4, + "height": 1, + "passthru": true, + "label": " STOP PUMP", + "tooltip": "", + "color": "", + "bgcolor": "#AD1625", + "icon": "fa-pause fa-2x", + "payload": "{\"action\":\"stop\"}", + "payloadType": "json", + "topic": "actuator/pump", + "x": 570, + "y": 240, + "wires": [ + [ + "bdc8ce57.de1f08" + ] + ] + }, + { + "id": "cfc783d7.d6ceb", + "type": "link in", + "z": "bccd1f23.87219", + "name": "Optics recalculation", + "links": [ + "559a8085.1d6b9", + "5d5ad36d2c50dcc2" + ], + "x": 915, + "y": 120, + "wires": [ + [ + "8038414a.34461" + ] + ] + }, + { + "id": "326a1d95.ca21aa", + "type": "subflow:1c24ad9c.bebec2", + "z": "bccd1f23.87219", + "name": "", + "x": 550, + "y": 1180, + "wires": [ + [] + ] + }, + { + "id": "2d371e59.b0e50a", + "type": "inject", + "z": "bccd1f23.87219", + "name": "Default: 1000µm/s", + "props": [ + { + "p": "payload" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "0.5", + "topic": "", + "payload": "1000", + "payloadType": "num", + "x": 130, + "y": 500, + "wires": [ + [ + "3a86de51.765b9a" + ] + ] + }, + { + "id": "167cda35.c9b6ae", + "type": "ui_button", + "z": "bccd1f23.87219", + "name": "", + "group": "fbd92986.1028c8", + "order": 3, + "width": 4, + "height": 1, + "passthru": false, + "label": "UP 100um", + "tooltip": "", + "color": "", + "bgcolor": "", + "icon": "fa-angle-up fa-3x", + "payload": "{\"action\":\"move\",\"direction\":\"UP\",\"distance\":0.1}", + "payloadType": "json", + "topic": "actuator/focus", + "topicType": "str", + "x": 570, + "y": 640, + "wires": [ + [ + "62030521.88317c" + ] + ] + }, + { + "id": "72a7c597.9374fc", + "type": "ui_button", + "z": "bccd1f23.87219", + "name": "", + "group": "fbd92986.1028c8", + "order": 6, + "width": 4, + "height": 1, + "passthru": false, + "label": "DOWN 100um", + "tooltip": "", + "color": "", + "bgcolor": "", + "icon": "fa-angle-down fa-3x", + "payload": "{\"action\":\"move\",\"direction\":\"DOWN\",\"distance\":0.1}", + "payloadType": "json", + "topic": "actuator/focus", + "topicType": "str", + "x": 580, + "y": 680, + "wires": [ + [ + "62030521.88317c" + ] + ] + }, + { + "id": "f0775525.cf806", + "type": "ui_multistate_switch", + "z": "bccd1f23.87219", + "name": "light_control", + "group": "4248342d.e55fac", + "order": 1, + "width": 6, + "height": 1, + "label": "Light ", + "stateField": "payload", + "enableField": "enable", + "rounded": true, + "useThemeColors": true, + "hideSelectedLabel": false, + "options": [ + { + "label": "Off", + "value": "off", + "valueType": "str", + "color": "#009933" + }, + { + "label": "On", + "value": "on", + "valueType": "str", + "color": "#999999" + } + ], + "x": 310, + "y": 120, + "wires": [ + [ + "99ae4886.8d43c" + ] + ] + }, + { + "id": "99ae4886.8d43c", + "type": "function", + "z": "bccd1f23.87219", + "name": "Prepare message", + "func": "msg.topic = \"light\"\nmsg.payload = {\"action\":msg.payload}\n\nvar led_output = flow.get('led_output')\nif (led_output !== undefined && led_output !== \"\") {\n msg.payload[\"led\"] = led_output\n}\n\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 490, + "y": 120, + "wires": [ + [ + "d31fcead.7e2ef" + ] + ] + }, + { + "id": "d31fcead.7e2ef", + "type": "mqtt out", + "z": "bccd1f23.87219", + "name": "", + "topic": "", + "qos": "", + "retain": "", + "broker": "8dc3722c.06efa8", + "x": 650, + "y": 120, + "wires": [] + }, + { + "id": "4535ab65.009354", + "type": "ui_multistate_switch", + "z": "bccd1f23.87219", + "name": "led_output", + "group": "4248342d.e55fac", + "order": 2, + "width": 6, + "height": 1, + "label": "LED output", + "stateField": "payload", + "enableField": "enable", + "rounded": true, + "useThemeColors": true, + "hideSelectedLabel": false, + "options": [ + { + "label": "1", + "value": "1", + "valueType": "num", + "color": "#009933" + }, + { + "label": "2", + "value": "2", + "valueType": "num", + "color": "#999999" + } + ], + "x": 310, + "y": 180, + "wires": [ + [ + "152f58e5.ca51df" + ] + ] + }, + { + "id": "703d6ecd.62af88", + "type": "inject", + "z": "bccd1f23.87219", + "name": "Default: 1", + "props": [ + { + "p": "payload" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": 0.1, + "topic": "", + "payload": "1", + "payloadType": "num", + "x": 120, + "y": 180, + "wires": [ + [ + "4535ab65.009354" + ] + ] + }, + { + "id": "152f58e5.ca51df", + "type": "change", + "z": "bccd1f23.87219", + "name": "", + "rules": [ + { + "t": "set", + "p": "led_output", + "pt": "flow", + "to": "payload", + "tot": "msg" + }, + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "on", + "tot": "str" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 480, + "y": 180, + "wires": [ + [ + "f0775525.cf806", + "99ae4886.8d43c" + ] + ] + }, + { + "id": "8ea9dc9a.c7d87", + "type": "function", + "z": "bccd1f23.87219", + "name": "Encapsulate settings", + "func": "msg.payload = {\n \"action\":\"settings\", \n \"settings\":{[msg.topic]:msg.payload}\n}\n\nmsg.topic = \"imager/image\"\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 1120, + "y": 940, + "wires": [ + [ + "845e06e1.0d812" + ] + ] + }, + { + "id": "5765a825.a595c8", + "type": "ui_slider", + "z": "bccd1f23.87219", + "name": "Shutter speed slider", + "label": "Shutter Speed", + "tooltip": "In microseconds, up to 1000µs, 125µs by default", + "group": "8c38a81e.9897a8", + "order": 4, + "width": 0, + "height": 0, + "passthru": true, + "outs": "end", + "topic": "shutter_speed", + "topicType": "str", + "min": "125", + "max": "1000", + "step": "1", + "className": "", + "x": 600, + "y": 880, + "wires": [ + [ + "8ea9dc9a.c7d87" + ] + ] + }, + { + "id": "845e06e1.0d812", + "type": "mqtt out", + "z": "bccd1f23.87219", + "name": "", + "topic": "", + "qos": "", + "retain": "", + "broker": "8dc3722c.06efa8", + "x": 1390, + "y": 980, + "wires": [] + }, + { + "id": "2350e507.d4e302", + "type": "inject", + "z": "bccd1f23.87219", + "name": "Default: 125µs", + "props": [ + { + "p": "payload" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "1", + "topic": "", + "payload": "125", + "payloadType": "num", + "x": 120, + "y": 880, + "wires": [ + [ + "5765a825.a595c8" + ] + ] + }, + { + "id": "5e147425.7666ec", + "type": "function", + "z": "bccd1f23.87219", + "name": "Encapsulate wb gain settings", + "func": "msg.payload = {\n \"action\":\"settings\", \n \"settings\":{\"white_balance_gain\":{\n [msg.topic]:Math.round(msg.payload*100)\n }\n }\n}\nmsg.topic = \"imager/image\"\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 1100, + "y": 1060, + "wires": [ + [ + "845e06e1.0d812" + ] + ] + }, + { + "id": "82722a3c.846b3", + "type": "inject", + "z": "bccd1f23.87219", + "name": "Default: OFF", + "props": [ + { + "p": "payload" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "1", + "topic": "", + "payload": "false", + "payloadType": "bool", + "x": 110, + "y": 920, + "wires": [ + [ + "60e44330.50bdec" + ] + ] + }, + { + "id": "60e44330.50bdec", + "type": "ui_switch", + "z": "bccd1f23.87219", + "name": "AWB", + "label": "Auto White Balance", + "tooltip": "", + "group": "8c38a81e.9897a8", + "order": 5, + "width": 2, + "height": 2, + "passthru": true, + "decouple": "false", + "topic": "white_balance", + "topicType": "str", + "style": "", + "onvalue": "auto", + "onvalueType": "str", + "onicon": "", + "oncolor": "", + "offvalue": "off", + "offvalueType": "str", + "officon": "", + "offcolor": "", + "animate": true, + "className": "", + "x": 550, + "y": 920, + "wires": [ + [ + "8ea9dc9a.c7d87" + ] + ] + }, + { + "id": "6be64480.7e7e24", + "type": "change", + "z": "bccd1f23.87219", + "name": "Get red_gain", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "payload.red_gain", + "tot": "msg" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 370, + "y": 1040, + "wires": [ + [ + "d5415af6.e06cc" + ] + ] + }, + { + "id": "6d49d161.13628", + "type": "change", + "z": "bccd1f23.87219", + "name": "Get blue_gain", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "payload.blue_gain", + "tot": "msg" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 380, + "y": 1080, + "wires": [ + [ + "dba68c1f.e3144" + ] + ] + }, + { + "id": "56835fa1.2fe538", + "type": "subflow:4ed26b8b.253504", + "z": "bccd1f23.87219", + "name": "", + "env": [], + "x": 1160, + "y": 1020, + "wires": [] + }, + { + "id": "8ef294ba.12213", + "type": "change", + "z": "bccd1f23.87219", + "name": "Get analog_gain", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "1", + "tot": "num" + }, + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "payload.analog_gain", + "tot": "msg" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 380, + "y": 960, + "wires": [ + [ + "a6c7eec4.f7a918" + ] + ] + }, + { + "id": "8e336e58.14722", + "type": "change", + "z": "bccd1f23.87219", + "name": "Get digital_gain", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "1", + "tot": "num" + }, + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "payload.digital_gain", + "tot": "msg" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 380, + "y": 1000, + "wires": [ + [ + "66b37eef.f3f9e" + ] + ] + }, + { + "id": "a6c7eec4.f7a918", + "type": "ui_text_input", + "z": "bccd1f23.87219", + "d": true, + "name": "Analog gain field", + "label": "Analog Gain", + "tooltip": "From 1.0 to 12.0", + "group": "8c38a81e.9897a8", + "order": 1, + "width": 0, + "height": 0, + "passthru": true, + "mode": "number", + "delay": 300, + "topic": "analog", + "topicType": "str", + "x": 580, + "y": 960, + "wires": [ + [ + "44e02933.a66688", + "d361a2c4.0990f8" + ] + ] + }, + { + "id": "66b37eef.f3f9e", + "type": "ui_text_input", + "z": "bccd1f23.87219", + "d": true, + "name": "Digital gain field", + "label": "Digital Gain", + "tooltip": "From 1.0 to 64.0. Overexpose starting at 4.0", + "group": "8c38a81e.9897a8", + "order": 2, + "width": 0, + "height": 0, + "passthru": true, + "mode": "number", + "delay": 300, + "topic": "digital", + "topicType": "str", + "x": 580, + "y": 1000, + "wires": [ + [ + "44e02933.a66688", + "d361a2c4.0990f8" + ] + ] + }, + { + "id": "44e02933.a66688", + "type": "function", + "z": "bccd1f23.87219", + "name": "Encapsulate image gain settings", + "func": "msg.payload = {\n \"action\":\"settings\", \n \"settings\":{\"image_gain\":{\n [msg.topic]:Math.round(msg.payload*100)\n }\n }\n}\nmsg.topic = \"imager/image\"\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 1090, + "y": 980, + "wires": [ + [ + "845e06e1.0d812" + ] + ] + }, + { + "id": "d361a2c4.0990f8", + "type": "change", + "z": "bccd1f23.87219", + "name": "topic *_gain", + "rules": [ + { + "t": "set", + "p": "topic", + "pt": "msg", + "to": "topic&'_gain'", + "tot": "jsonata" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 970, + "y": 1020, + "wires": [ + [ + "56835fa1.2fe538" + ] + ] + }, + { + "id": "d8d006bf.2947f", + "type": "inject", + "z": "bccd1f23.87219", + "name": "Default: ISO 100", + "props": [ + { + "p": "payload" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "1", + "topic": "", + "payload": "100", + "payloadType": "num", + "x": 130, + "y": 840, + "wires": [ + [ + "9feb06fb.43b558" + ] + ] + }, + { + "id": "9feb06fb.43b558", + "type": "ui_multistate_switch", + "z": "bccd1f23.87219", + "name": "ISO selector", + "group": "8c38a81e.9897a8", + "order": 3, + "width": 0, + "height": 0, + "label": "ISO", + "stateField": "payload", + "enableField": "enable", + "passthroughField": "passthrough", + "inputMsgField": "inputmsg", + "rounded": true, + "useThemeColors": true, + "hideSelectedLabel": false, + "multilineLabel": false, + "passThrough": "never", + "inputMsg": "all", + "userInput": "enabled_show", + "options": [ + { + "label": "100", + "value": "100", + "valueType": "num", + "color": "#009933" + }, + { + "label": "200", + "value": "200", + "valueType": "num", + "color": "#999999" + }, + { + "label": "320", + "value": "320", + "valueType": "num", + "color": "#ff6666" + }, + { + "label": "400", + "value": "400", + "valueType": "num", + "color": "#009999" + }, + { + "label": "500", + "value": "500", + "valueType": "num", + "color": "#cccc00" + }, + { + "label": "640", + "value": "640", + "valueType": "num", + "color": "#ff33cc" + }, + { + "label": "800", + "value": "800", + "valueType": "num", + "color": "#cc6600" + } + ], + "x": 570, + "y": 840, + "wires": [ + [ + "eb9966de.cf13c8" + ] + ] + }, + { + "id": "eb9966de.cf13c8", + "type": "change", + "z": "bccd1f23.87219", + "name": "", + "rules": [ + { + "t": "set", + "p": "topic", + "pt": "msg", + "to": "iso", + "tot": "str" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 740, + "y": 840, + "wires": [ + [ + "8ea9dc9a.c7d87" + ] + ] + }, + { + "id": "be33e564.029358", + "type": "ui_text_input", + "z": "bccd1f23.87219", + "name": "focus_distance", + "label": "Focus Distance (in µm)", + "tooltip": "in µm, 25µm resolution", + "group": "fbd92986.1028c8", + "order": 4, + "width": 0, + "height": 0, + "passthru": true, + "mode": "number", + "delay": 300, + "topic": "focus_distance", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 580, + "y": 460, + "wires": [ + [ + "dc48dc42.98d18" + ] + ] + }, + { + "id": "3a86de51.765b9a", + "type": "ui_text_input", + "z": "bccd1f23.87219", + "name": "focus_speed", + "label": "Focus Speed (in µm/sec)", + "tooltip": "in µm/sec", + "group": "fbd92986.1028c8", + "order": 5, + "width": 0, + "height": 0, + "passthru": true, + "mode": "number", + "delay": 300, + "topic": "focus_speed", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 570, + "y": 500, + "wires": [ + [ + "dc48dc42.98d18" + ] + ] + }, + { + "id": "cb2d5174.cfe9f", + "type": "ui_text_input", + "z": "bccd1f23.87219", + "name": "pump_flowrate", + "label": "Flowrate (ml/min)*", + "tooltip": "", + "group": "707d9797.c8e798", + "order": 1, + "width": 0, + "height": 0, + "passthru": true, + "mode": "text", + "delay": 300, + "topic": "pump_flowrate", + "topicType": "str", + "x": 580, + "y": 380, + "wires": [ + [ + "dc48dc42.98d18" + ] + ] + }, + { + "id": "dba68c1f.e3144", + "type": "ui_text_input", + "z": "bccd1f23.87219", + "name": "WB Blue input", + "label": "WB: Blue", + "tooltip": "From 1.0 to 64.0", + "group": "8c38a81e.9897a8", + "order": 7, + "width": 4, + "height": 1, + "passthru": true, + "mode": "number", + "delay": "0", + "topic": "blue", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 580, + "y": 1080, + "wires": [ + [ + "3ece53716a02e09e" + ] + ] + }, + { + "id": "335a730b9a3830ff", + "type": "ui_template", + "z": "bccd1f23.87219", + "group": "4248342d.e55fac", + "name": "Lens", + "order": 3, + "width": 0, + "height": 0, + "format": "
\n Objective lens aperture: \n \n mm\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": false, + "templateScope": "local", + "x": 1310, + "y": 40, + "wires": [ + [] + ] + }, + { + "id": "33ef60a6a80aa3a7", + "type": "subflow:b7861ce703215a01", + "z": "bccd1f23.87219", + "name": "", + "x": 160, + "y": 1020, + "wires": [ + [ + "8ef294ba.12213", + "8e336e58.14722", + "6be64480.7e7e24", + "6d49d161.13628" + ] + ] + }, + { + "id": "a3d034643b56796f", + "type": "inject", + "z": "bccd1f23.87219", + "name": "Once", + "props": [], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": 0.1, + "topic": "", + "x": 70, + "y": 1080, + "wires": [ + [ + "33ef60a6a80aa3a7" + ] + ] + }, + { + "id": "5984b086eddc9311", + "type": "link in", + "z": "bccd1f23.87219", + "name": "Load hardware config", + "links": [ + "3973b999ee7b3b1d", + "5d3df1564b9af89c" + ], + "x": 25, + "y": 1000, + "wires": [ + [ + "33ef60a6a80aa3a7" + ] + ] + }, + { + "id": "d5415af6.e06cc", + "type": "ui_text_input", + "z": "bccd1f23.87219", + "name": "WB Red input", + "label": "WB: Red", + "tooltip": "From 1.0 to 8.0", + "group": "8c38a81e.9897a8", + "order": 6, + "width": 4, + "height": 1, + "passthru": true, + "mode": "number", + "delay": "0", + "topic": "red", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 580, + "y": 1040, + "wires": [ + [ + "01c2b633558b0b02" + ] + ] + }, + { + "id": "01c2b633558b0b02", + "type": "switch", + "z": "bccd1f23.87219", + "name": "Validate", + "property": "payload", + "propertyType": "msg", + "rules": [ + { + "t": "btwn", + "v": "1.0", + "vt": "num", + "v2": "8.0", + "v2t": "num" + }, + { + "t": "else" + } + ], + "checkall": "false", + "repair": false, + "outputs": 2, + "x": 740, + "y": 1040, + "wires": [ + [ + "d361a2c4.0990f8", + "5e147425.7666ec" + ], + [ + "cbfaf049d92be90e", + "5d3df1564b9af89c" + ] + ] + }, + { + "id": "3ece53716a02e09e", + "type": "switch", + "z": "bccd1f23.87219", + "name": "Validate", + "property": "payload", + "propertyType": "msg", + "rules": [ + { + "t": "btwn", + "v": "1.0", + "vt": "num", + "v2": "8.0", + "v2t": "num" + }, + { + "t": "else" + } + ], + "checkall": "false", + "repair": false, + "outputs": 2, + "x": 740, + "y": 1080, + "wires": [ + [ + "d361a2c4.0990f8", + "5e147425.7666ec" + ], + [ + "cbfaf049d92be90e", + "5d3df1564b9af89c" + ] + ] + }, + { + "id": "cbfaf049d92be90e", + "type": "ui_toast", + "z": "bccd1f23.87219", + "position": "top right", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 0, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "Invalid white balance value", + "name": "", + "x": 990, + "y": 1100, + "wires": [] + }, + { + "id": "5d3df1564b9af89c", + "type": "link out", + "z": "bccd1f23.87219", + "name": "Reload hardware config", + "mode": "link", + "links": [ + "5984b086eddc9311" + ], + "x": 915, + "y": 1140, + "wires": [] + }, + { + "id": "6b34c456.83178c", + "type": "ui_text_input", + "z": "baa1e3d9.cb29d", + "name": "acq_id", + "label": "Acquisition unique ID*", + "tooltip": "", + "group": "4322c187.e73e5", + "order": 1, + "width": 5, + "height": 1, + "passthru": true, + "mode": "text", + "delay": 300, + "topic": "acq_id", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 690, + "y": 180, + "wires": [ + [ + "fb887036.12429" + ] + ] + }, + { + "id": "cc0ca68b.4263a8", + "type": "ui_dropdown", + "z": "baa1e3d9.cb29d", + "name": "acq_celltype", + "label": "Flowcell thickness*", + "tooltip": "", + "place": "Select option", + "group": "4322c187.e73e5", + "order": 6, + "width": 5, + "height": 1, + "passthru": true, + "multiple": false, + "options": [ + { + "label": "200 μm µ-Slide I Luer", + "value": 200, + "type": "num" + }, + { + "label": "300 µm capillary", + "value": 300, + "type": "num" + }, + { + "label": "400 μm µ-Slide I Luer", + "value": 400, + "type": "num" + }, + { + "label": "600 μm µ-Slide I Luer", + "value": 600, + "type": "num" + }, + { + "label": "800 μm µ-Slide I Luer", + "value": 800, + "type": "num" + } + ], + "payload": "", + "topic": "acq_celltype", + "topicType": "str", + "className": "", + "x": 670, + "y": 100, + "wires": [ + [ + "fb887036.12429", + "99b11fe4.2795d" + ] + ] + }, + { + "id": "fb887036.12429", + "type": "function", + "z": "baa1e3d9.cb29d", + "name": "set global", + "func": "global.set(msg.topic, msg.payload);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 920, + "y": 180, + "wires": [ + [ + "52ea7d01.711034" + ] + ] + }, + { + "id": "bb2bb7ce.1d1458", + "type": "ui_template", + "z": "baa1e3d9.cb29d", + "group": "858a0e3c.987fe", + "name": "Stream Pi Camera", + "order": 1, + "width": 10, + "height": 8, + "format": "
\n \"If\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 550, + "y": 40, + "wires": [ + [] + ] + }, + { + "id": "d0c5b57d.590818", + "type": "ui_ui_control", + "z": "baa1e3d9.cb29d", + "name": "", + "events": "change", + "x": 1280, + "y": 660, + "wires": [ + [] + ] + }, + { + "id": "c72f8fae.23bd4", + "type": "ui_button", + "z": "baa1e3d9.cb29d", + "name": "", + "group": "b7919ae2.c01788", + "order": 1, + "width": 5, + "height": 1, + "passthru": false, + "label": "Previous", + "tooltip": "", + "color": "#097479", + "bgcolor": "white", + "icon": "keyboard_return", + "payload": "{\"tab\":\"Optic Configuration\"}", + "payloadType": "json", + "topic": "", + "x": 1140, + "y": 660, + "wires": [ + [ + "d0c5b57d.590818" + ] + ] + }, + { + "id": "29be525e.0c87fe", + "type": "ui_template", + "z": "baa1e3d9.cb29d", + "group": "b5d61bc7.54fe48", + "name": "Show Metadata", + "order": 9, + "width": 0, + "height": 0, + "format": "
\n \n \n \n \n \n \n \n \n \n
\n

Sample

\n

id:

\n

project:\n

\n

ship:

\n

operator:\n

\n

sampling gear:\n

\n

concentrated volume:\n

\n

gear net opening:\n

\n

total volume filtered:\n

\n
\n

Acquisition

\n

id:

\n

instrument:\n

\n

instrument id:\n

\n

camera:

\n

celltype: \n

\n

minimum mesh:\n

\n

maximum mesh:\n

\n

min esd: \n

\n

max esd: \n

\n

volume:

\n

magnification:\n

\n

fnumber objective:\n

\n

software: \n

\n
\n

Object

\n

latitude: \n

\n

longitude: \n

\n

latitude end:\n

\n

longitude end:\n

\n

date:

\n

time:

\n

date end:\n

\n

time end:\n

\n

depth min:\n

\n

depth max:\n

\n
\n

Process

\n

pixel: \n

\n

id:

\n
\n
", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 1160, + "y": 380, + "wires": [ + [] + ] + }, + { + "id": "4b489713.ccde5", + "type": "ui_button", + "z": "baa1e3d9.cb29d", + "name": "", + "group": "4322c187.e73e5", + "order": 12, + "width": 5, + "height": 1, + "passthru": false, + "label": "Start Acquisition", + "tooltip": "", + "color": "", + "bgcolor": "", + "icon": "camera", + "payload": "", + "payloadType": "str", + "topic": "imager/image", + "x": 420, + "y": 440, + "wires": [ + [ + "c9f510c0.7d1328" + ] + ] + }, + { + "id": "c9f510c0.7d1328", + "type": "function", + "z": "baa1e3d9.cb29d", + "name": "Image control", + "func": "// Reset the number of images taken\nflow.set('img_counter', 0);\n\nvar acq_celltype = global.get(\"acq_celltype\");\nvar acq_minimum_mesh = global.get(\"acq_minimum_mesh\");\nvar acq_maximum_mesh = global.get(\"acq_maximum_mesh\");\nvar imaging_pump_volume = global.get(\"imaging_pump_volume\");\nvar acq_id = global.get(\"acq_id\");\nvar nb_frame = global.get(\"nb_frame\");\nvar pump_direction = global.get(\"pump_direction\");\nvar sleep_before = global.get(\"sleep_before\");\nvar object_date = global.get(\"object_date\");\n\nif (acq_celltype === undefined || acq_celltype === \"\") {\n msg.topic = \"Missing entry :\";\n msg.payload = \"Type of the flowcell\";\n return [null, msg];\n} else if (acq_minimum_mesh === undefined || acq_minimum_mesh === \"\") {\n msg.topic = \"Missing entry :\";\n msg.payload = \"Lower fraction size\";\n return [null, msg];\n} else if (acq_maximum_mesh === undefined || acq_maximum_mesh === \"\") {\n msg.topic = \"Missing entry :\";\n msg.payload = \"Upper fraction size\";\n return [null, msg];\n} else if (imaging_pump_volume === undefined || imaging_pump_volume === \"\" || imaging_pump_volume === null) {\n msg.topic = \"Missing entry :\";\n msg.payload = \"Volume inbetween images\";\n return [null, msg];\n} else if (acq_id === undefined || acq_id === \"\") {\n msg.topic = \"Missing entry :\";\n msg.payload = \"Acquisition ID\";\n return [null, msg];\n} else if (nb_frame === undefined || nb_frame === \"\" || nb_frame === null) {\n msg.topic = \"Missing entry :\";\n msg.payload = \"Number of image to save\";\n return [null, msg];\n} else if (pump_direction === undefined || pump_direction === \"\" || pump_direction === null) {\n msg.topic = \"Missing entry :\";\n msg.payload = \"Pump direction\";\n return [null, msg];\n} else if (sleep_before === undefined || sleep_before === \"\" || sleep_before === null) {\n msg.topic = \"Missing entry :\";\n msg.payload = \"Delay before image\";\n return [null, msg];\n}else if (object_date === undefined || object_date === \"\" || object_date === null) {\n msg.topic = \"Missing entry :\";\n msg.payload = \"Object date\";\n return [null, msg];\n}\n\nmsg.payload = {\n \"action\": \"image\",\n \"sleep\": sleep_before,\n \"pump_direction\": pump_direction,\n \"volume\": imaging_pump_volume,\n \"nb_frame\": nb_frame,\n}\nmsg.send = true\n\nreturn [msg, null];", + "outputs": 2, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 640, + "y": 440, + "wires": [ + [ + "52ea7d01.711034", + "40c12463.a1f84c", + "a4abb1ae.2ae418" + ], + [ + "20e0a8c8.edbeb" + ] + ] + }, + { + "id": "20e0a8c8.edbeb", + "type": "ui_toast", + "z": "baa1e3d9.cb29d", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "topic": "", + "name": "", + "x": 890, + "y": 520, + "wires": [ + [] + ] + }, + { + "id": "c3e50240.82aa58", + "type": "mqtt out", + "z": "baa1e3d9.cb29d", + "name": "", + "topic": "", + "qos": "", + "retain": "", + "broker": "8dc3722c.06efa8", + "x": 1130, + "y": 420, + "wires": [] + }, + { + "id": "3a4450b1.4459a8", + "type": "ui_button", + "z": "baa1e3d9.cb29d", + "name": "Stop Acquisition", + "group": "4322c187.e73e5", + "order": 11, + "width": 5, + "height": 1, + "passthru": true, + "label": "STOP ACQUISITION", + "tooltip": "", + "color": "", + "bgcolor": "#AD1625", + "icon": "cancel", + "payload": "{\"action\":\"stop\"}", + "payloadType": "json", + "topic": "imager/image", + "x": 420, + "y": 480, + "wires": [ + [ + "d74210ef.edc15" + ] + ] + }, + { + "id": "d74210ef.edc15", + "type": "mqtt out", + "z": "baa1e3d9.cb29d", + "name": "", + "topic": "", + "qos": "", + "retain": "", + "broker": "8dc3722c.06efa8", + "x": 610, + "y": 480, + "wires": [] + }, + { + "id": "bb62da8a.ebc328", + "type": "ui_switch", + "z": "baa1e3d9.cb29d", + "name": "Pump direction", + "label": "Pump direction", + "tooltip": "BACKWARD / FORWARD", + "group": "4322c187.e73e5", + "order": 9, + "width": 5, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "pump_direction", + "style": "", + "onvalue": "FORWARD", + "onvalueType": "str", + "onicon": "", + "oncolor": "", + "offvalue": "BACKWARD", + "offvalueType": "str", + "officon": "", + "offcolor": "", + "x": 420, + "y": 520, + "wires": [ + [ + "6b2239f3.41fa3" + ] + ] + }, + { + "id": "52ea7d01.711034", + "type": "function", + "z": "baa1e3d9.cb29d", + "name": "Encapsulate config", + "func": "msg.payload = {\n\t\"action\": \"update_config\",\n\t\"config\": {\n \t\"description\": {\n \t\t\"sample_project\": \"Project's name\",\n \t\t\"sample_id\": \"Sample ID\",\n \t\t\"sample_uuid\": \"Sample UUID (Autogenerated)\",\n \t\t\"sample_ship\": \"Ship's name\",\n \t\t\"sample_operator\": \"Operator's name\",\n \t\t\"sample_sampling_gear\": \"Sampling gear used\",\n \t\t\"sample_concentrated_sample_volume\": \"Volume of concentrated sample, in mL\",\n \t\t\"sample_total_volume\": \"Total volume filtered by the net used, in L\",\n \t\t\"sample_dilution_factor\": \"Dilution factor of the sample, 0.5 if diluted by 2, 2 if concentrated by 2\",\n \t\t\"sample_speed_through_water\": \"Speed of the boat through water when sampling, in kts\",\n \t\t\"acq_id\": \"Acquisition ID\",\n \t\t\"acq_uuid\": \"Acquisition UUID (Autogenerated)\",\n \t\t\"acq_instrument\": \"Instrument type\",\n \t\t\"acq_instrument_id\": \"Instrument ID\",\n \t\t\"acq_celltype\": \"Flow cell dimension thickness, in µm\",\n \t\t\"acq_minimum_mesh\": \"Minimum filtration mesh size, in µm\",\n \t\t\"acq_maximum_mesh\": \"Maximum filtration mesh size, in µm\",\n \t\t\"acq_min_esd\": \"\",\n \t\t\"acq_max_esd\": \"\",\n \t\t\"acq_volume\": \"Pumped volume, in mL\",\n\t\t \"acq_imaged_volume\": \"Total imaged volume, in mL\",\n \t\t\"acq_magnification\": \"Optical magnification\",\n \t\t\"acq_fnumber_objective\": \"Focal length of the objective, in mm\",\n \t\t\"acq_camera_name\": \"Name of the camera used\",\n \t\t\"acq_nb_frame\": \"Number of picture taken\",\n \"acq_local_datetime\": \"Instrument local datetime\",\n \"acq_camera_resolution\": \"Resolution of the images\",\n \"acq_camera_iso\": \"ISO Number of the images\",\n \"acq_camera_shutter_speed\": \"Shutter speed of the images, in µs\",\n \"acq_software\": \"Software version number\",\n \t\t\"object_date\": \"Sample collection date (or beginning if using a net)\",\n \t\t\"object_time\": \"Sample collection time (or beginning if using a net)\",\n \t\t\"object_lat\": \"Sample collection latitude (or beginning if using a net)\",\n \t\t\"object_lon\": \"Sample collection longitude (or beginning if using a net)\",\n \t\t\"object_depth_min\": \"Sample collection minimal depth, in m\",\n \t\t\"object_depth_max\": \"Sample collection maximum depth, in m\",\n \t\t\"process_pixel\": \"Pixel imaging resolution, in µm/pixel\",\n \t\t\"process_datetime\": \"Segmentation timestamp\",\n \t\t\"process_id\": \"Segmentation ID\",\n \t\t\"process_uuid\": \"Segmentation UUID (Autogenerated)\",\n \t\t\"process_source\": \"Code source link of the executed code\",\n \t\t\"process_commit\": \"Version reference of the executed code\",\n \t\t\"sample_gear_net_opening\": \"Sample mouth opening dimension, in mm\",\n \t\t\"object_date_end\": \"Sample end collection date when using a net\",\n \t\t\"object_time_end\": \"Sample end collection time when using a net\",\n \t\t\"object_lat_end\": \"Sample end collection latitude when using a net\",\n \t\t\"object_lon_end\": \"Sample end collection longitude when using a net\",\n \t},\n\t\t\"sample_project\": global.get(\"sample_project\"),\n\t\t\"sample_id\": global.get(\"sample_project\") + \"_\" + global.get(\"sample_id\"),\n\t\t\"sample_ship\": global.get(\"sample_ship\"),\n\t\t\"sample_operator\": global.get(\"sample_operator\"),\n\t\t\"sample_sampling_gear\": global.get(\"sample_sampling_gear\"),\n\t\t\"sample_concentrated_sample_volume\": global.get(\"sample_concentrated_sample_volume\"),\n\t\t\"sample_total_volume\": global.get(\"sample_total_volume\"),\n\t\t\"sample_dilution_factor\": global.get(\"sample_dilution_factor\"),\n\t\t\"sample_speed_through_water\": global.get(\"sample_speed_through_water\"),\n\n\t\t\"acq_id\": global.get(\"sample_project\") + \"_\" + global.get(\"sample_id\")+ \"_\" + global.get(\"acq_id\"),\n\t\t\"acq_instrument\": global.get(\"acq_instrument\"),\n\t\t\"acq_instrument_id\": global.get(\"acq_instrument_id\"),\n\t\t\"acq_celltype\": global.get(\"acq_celltype\"),\n\t\t\"acq_minimum_mesh\": global.get(\"acq_minimum_mesh\"),\n\t\t\"acq_maximum_mesh\": global.get(\"acq_maximum_mesh\"),\n\t\t\"acq_min_esd\": global.get(\"acq_min_esd\"),\n\t\t\"acq_max_esd\": global.get(\"acq_max_esd\"),\n\t\t\"acq_volume\": global.get(\"acq_volume\"),\n\t\t\"acq_imaged_volume\": global.get(\"acq_imaged_volume\"),\n\t\t\"acq_magnification\": global.get(\"acq_magnification\"),\n\t\t\"acq_fnumber_objective\": global.get(\"acq_fnumber_objective\"),\n\t\t\"acq_camera\": global.get(\"acq_camera\"),\n\t\t\"acq_nb_frame\": global.get(\"nb_frame\"),\n\t\t\"acq_software\": global.get(\"acq_software\"),\n\n\t\t\"object_date\": global.get(\"object_date\"),\n\t\t\"object_time\": global.get(\"object_time\"),\n\t\t\"object_lat\": global.get(\"object_lat\"),\n\t\t\"object_lon\": global.get(\"object_lon\"),\n\t\t\"object_depth_min\": global.get(\"object_depth_min\"),\n\t\t\"object_depth_max\": global.get(\"object_depth_max\"),\n\n\t\t\"process_pixel\": global.get(\"process_pixel\"),\n\t\t\"process_source\": global.get(\"process_source\"),\n\t\t\"process_commit\": global.get(\"process_commit\")\n\t}\n};\n\nif (msg.payload.config.sample_sampling_gear.startsWith(\"net\")) {\n\tmsg.payload.config[\"sample_gear_net_opening\"] = global.get(\"sample_gear_net_opening\")\n\tmsg.payload.config[\"object_date_end\"] = global.get(\"object_date_end\")\n\tmsg.payload.config[\"object_time_end\"] = global.get(\"object_time_end\")\n\tmsg.payload.config[\"object_lat_end\"] = global.get(\"object_lat_end\")\n\tmsg.payload.config[\"object_lon_end\"] = global.get(\"object_lon_end\")\n}\n\nif ( msg.send == true){\n\treturn [msg, msg]\n}\nelse{\n\treturn [msg, null]\n}", + "outputs": 2, + "timeout": "", + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 870, + "y": 400, + "wires": [ + [ + "29be525e.0c87fe" + ], + [ + "c3e50240.82aa58" + ] + ] + }, + { + "id": "40c12463.a1f84c", + "type": "delay", + "z": "baa1e3d9.cb29d", + "name": "", + "pauseType": "delay", + "timeout": "1", + "timeoutUnits": "seconds", + "rate": "1", + "nbRateUnits": "1", + "rateUnits": "second", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": false, + "outputs": 1, + "x": 900, + "y": 440, + "wires": [ + [ + "c3e50240.82aa58" + ] + ] + }, + { + "id": "4d1b02cb.83b51c", + "type": "ui_button", + "z": "baa1e3d9.cb29d", + "name": "", + "group": "4322c187.e73e5", + "order": 10, + "width": 5, + "height": 1, + "passthru": false, + "label": "Update config", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "save", + "payload": "", + "payloadType": "str", + "topic": "imager/image", + "topicType": "str", + "x": 420, + "y": 400, + "wires": [ + [ + "52ea7d01.711034" + ] + ] + }, + { + "id": "5921d0d0.a3d568", + "type": "subflow:1c24ad9c.bebec2", + "z": "baa1e3d9.cb29d", + "name": "", + "env": [], + "x": 110, + "y": 180, + "wires": [ + [ + "f3658d30.b8448", + "de2c90cf.b73b08", + "4be09c97f86897d9", + "f573206abefa9518", + "f948151ab4031df4" + ] + ] + }, + { + "id": "f3658d30.b8448", + "type": "function", + "z": "baa1e3d9.cb29d", + "name": "get acq_id", + "func": "msg.payload = msg.payload.acq_id;\nreturn msg;", + "outputs": 1, + "timeout": "", + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 330, + "y": 180, + "wires": [ + [ + "6b34c456.83178c" + ] + ] + }, + { + "id": "de2c90cf.b73b08", + "type": "function", + "z": "baa1e3d9.cb29d", + "name": "get acq_celltype", + "func": "msg.payload = msg.payload.acq_celltype;\nreturn msg;", + "outputs": 1, + "timeout": "", + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 340, + "y": 100, + "wires": [ + [ + "cc0ca68b.4263a8" + ] + ] + }, + { + "id": "b402f719.55bc98", + "type": "inject", + "z": "baa1e3d9.cb29d", + "name": "Default: FORWARD", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": 0.1, + "topic": "pump_direction", + "payload": "FORWARD", + "payloadType": "str", + "x": 180, + "y": 520, + "wires": [ + [ + "bb62da8a.ebc328" + ] + ] + }, + { + "id": "6b2239f3.41fa3", + "type": "function", + "z": "baa1e3d9.cb29d", + "name": "set global", + "func": "global.set(msg.topic, msg.payload);", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 620, + "y": 520, + "wires": [ + [] + ] + }, + { + "id": "51b4d0df.d70a88", + "type": "ui_text_input", + "z": "baa1e3d9.cb29d", + "name": "nb_frame", + "label": "Number of images to acquire", + "tooltip": "", + "group": "4322c187.e73e5", + "order": 2, + "width": 5, + "height": 1, + "passthru": true, + "mode": "number", + "delay": 300, + "topic": "nb_frame", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 680, + "y": 220, + "wires": [ + [ + "fb887036.12429", + "67091ac0.8f9f6c", + "99b11fe4.2795d" + ] + ] + }, + { + "id": "999065ca.27edb8", + "type": "switch", + "z": "baa1e3d9.cb29d", + "name": "topic filter", + "property": "topic", + "propertyType": "msg", + "rules": [ + { + "t": "eq", + "v": "status/pump", + "vt": "str" + }, + { + "t": "eq", + "v": "status/focus", + "vt": "str" + }, + { + "t": "eq", + "v": "status/light", + "vt": "str" + }, + { + "t": "eq", + "v": "status/imager", + "vt": "str" + } + ], + "checkall": "true", + "repair": false, + "outputs": 4, + "x": 320, + "y": 800, + "wires": [ + [ + "a46a1e7f.88a92", + "6742014e.1bb238" + ], + [ + "c516d9ea.f7f6e", + "6742014e.1bb238" + ], + [ + "6742014e.1bb238" + ], + [ + "307c851e.fb0f7a", + "2b9d6988.d84836" + ] + ] + }, + { + "id": "2b009bd7.c07004", + "type": "ui_text", + "z": "baa1e3d9.cb29d", + "group": "70de8209.68416c", + "order": 3, + "width": 10, + "height": 2, + "name": "imager", + "label": "Imager status:", + "format": "{{msg.payload.status}}", + "layout": "col-center", + "x": 770, + "y": 740, + "wires": [] + }, + { + "id": "c516d9ea.f7f6e", + "type": "ui_text", + "z": "baa1e3d9.cb29d", + "group": "70de8209.68416c", + "order": 1, + "width": 5, + "height": 1, + "name": "focus", + "label": "Focus status:", + "format": "{{msg.payload.status}}", + "layout": "col-center", + "x": 770, + "y": 700, + "wires": [] + }, + { + "id": "a46a1e7f.88a92", + "type": "ui_text", + "z": "baa1e3d9.cb29d", + "group": "70de8209.68416c", + "order": 2, + "width": 5, + "height": 1, + "name": "pump", + "label": "Pump status:", + "format": "{{msg.payload.status}}", + "layout": "col-center", + "x": 770, + "y": 660, + "wires": [] + }, + { + "id": "bb628f8d.98f108", + "type": "link in", + "z": "baa1e3d9.cb29d", + "name": "Status for fluidic module", + "links": [ + "58f2e0f.4e8b12" + ], + "x": 175, + "y": 800, + "wires": [ + [ + "999065ca.27edb8" + ] + ] + }, + { + "id": "307c851e.fb0f7a", + "type": "switch", + "z": "baa1e3d9.cb29d", + "name": "Imaging state", + "property": "payload", + "propertyType": "msg", + "rules": [ + { + "t": "jsonata_exp", + "v": "$contains(msg.payload.status, \"jpg\")\t", + "vt": "jsonata" + }, + { + "t": "else" + } + ], + "checkall": "false", + "repair": false, + "outputs": 2, + "x": 540, + "y": 880, + "wires": [ + [ + "db8e3dde.44efb8" + ], + [ + "6742014e.1bb238" + ] + ] + }, + { + "id": "db8e3dde.44efb8", + "type": "function", + "z": "baa1e3d9.cb29d", + "name": "img_counter", + "func": "img_counter=flow.get('img_counter')\nif (img_counter === undefined || img_counter === \"\"){\n img_counter = 0\n}\nimg_counter=img_counter+1\nflow.set('img_counter',img_counter)\nmsg.payload = img_counter\nmsg.payload = (100 * img_counter/global.get('nb_frame')).toFixed(2)\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 770, + "y": 860, + "wires": [ + [ + "1a2e721a.f5e876" + ] + ] + }, + { + "id": "59164d65.e7993c", + "type": "ui_toast", + "z": "baa1e3d9.cb29d", + "position": "top right", + "displayTime": "5", + "highlight": "", + "sendall": true, + "outputs": 0, + "ok": "OK", + "cancel": "", + "raw": false, + "topic": "", + "name": "", + "x": 1270, + "y": 900, + "wires": [] + }, + { + "id": "8c7348aa.1962e8", + "type": "template", + "z": "baa1e3d9.cb29d", + "name": "Create sentence", + "field": "payload", + "fieldType": "msg", + "format": "handlebars", + "syntax": "mustache", + "template": "The {{topic}} is {{payload.status}}", + "output": "str", + "x": 1050, + "y": 900, + "wires": [ + [ + "59164d65.e7993c" + ] + ] + }, + { + "id": "6742014e.1bb238", + "type": "change", + "z": "baa1e3d9.cb29d", + "name": "Remove high-level topic", + "rules": [ + { + "t": "change", + "p": "topic", + "pt": "msg", + "from": "status/", + "fromt": "str", + "to": "", + "tot": "str" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 810, + "y": 900, + "wires": [ + [ + "8c7348aa.1962e8" + ] + ] + }, + { + "id": "1a2e721a.f5e876", + "type": "ui_gauge", + "z": "baa1e3d9.cb29d", + "name": "progress donut", + "group": "b5d61bc7.54fe48", + "order": 3, + "width": 6, + "height": 3, + "gtype": "donut", + "title": "", + "label": "%", + "format": "{{value}}", + "min": 0, + "max": "100", + "colors": [ + "#ffa83f", + "#e6ff02", + "#00dfe9" + ], + "seg1": "50", + "seg2": "75", + "x": 1260, + "y": 860, + "wires": [] + }, + { + "id": "9bd72495.a8a098", + "type": "ui_text", + "z": "baa1e3d9.cb29d", + "group": "4322c187.e73e5", + "order": 5, + "width": 5, + "height": 1, + "name": "Total imaged volume", + "label": "Total imaged volume", + "format": "{{msg.payload}}", + "layout": "col-center", + "x": 1200, + "y": 100, + "wires": [] + }, + { + "id": "99b11fe4.2795d", + "type": "function", + "z": "baa1e3d9.cb29d", + "name": "imaged volume calc", + "func": "camera = global.get(\"acq_camera\");\ncell = global.get(\"acq_celltype\");\nnb_frame = global.get(\"nb_frame\");\nprocess_pixel = global.get(\"process_pixel\");\n\nvar volume = 0\nif (camera == \"HQ Camera\"){\n volume = nb_frame * (process_pixel*4056*process_pixel*3040*cell/1000000000) / 1000;\n}\nelse if (camera == \"Camera v2.1\"){\n volume = nb_frame * (process_pixel*3280*process_pixel*2464*cell/1000000000) / 1000;\n}\nelse{\n msg.payload = \"The camera is not known to this system\";\n return msg;\n}\n\nglobal.set(\"acq_imaged_volume\", volume.toFixed(4))\n\nmsg.payload = volume.toFixed(2) + \" mL\"\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 960, + "y": 100, + "wires": [ + [ + "9bd72495.a8a098" + ] + ], + "info": "### Focusing\n##### focus.py `nb_step` `orientation`\n\n- `nb_step` : **integer** (from 1 to 100000) - number of step to perform by the stage (about 31um/step)\n- `orientation` : **string** - orientation of the focus either `up` or `down`\n\nExample:\n\n python3.7 $HOME/PlanktoScope/scripts/focus.py 650 up\n" + }, + { + "id": "8e16aa2f.e40398", + "type": "ui_text", + "z": "baa1e3d9.cb29d", + "group": "4322c187.e73e5", + "order": 7, + "width": 5, + "height": 1, + "name": "Total pumped volume", + "label": "Total pumped volume", + "format": "{{msg.payload}} mL", + "layout": "col-center", + "x": 1200, + "y": 260, + "wires": [] + }, + { + "id": "67091ac0.8f9f6c", + "type": "function", + "z": "baa1e3d9.cb29d", + "name": "acq_volume calc", + "func": "var imaging_pump_volume = global.get(\"imaging_pump_volume\");\nvar nb_frame = global.get(\"nb_frame\");\nvar acq_volume = 0\n\nacq_volume = (Number(nb_frame)*Number(imaging_pump_volume)).toFixed(2)\nglobal.set(\"acq_volume\", acq_volume)\n\nmsg.payload = acq_volume\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 950, + "y": 260, + "wires": [ + [ + "8e16aa2f.e40398" + ] + ], + "info": "### Focusing\n##### focus.py `nb_step` `orientation`\n\n- `nb_step` : **integer** (from 1 to 100000) - number of step to perform by the stage (about 31um/step)\n- `orientation` : **string** - orientation of the focus either `up` or `down`\n\nExample:\n\n python3.7 $HOME/PlanktoScope/scripts/focus.py 650 up\n" + }, + { + "id": "2b9d6988.d84836", + "type": "switch", + "z": "baa1e3d9.cb29d", + "name": "", + "property": "payload", + "propertyType": "msg", + "rules": [ + { + "t": "hask", + "v": "status", + "vt": "str" + }, + { + "t": "hask", + "v": "camera_name", + "vt": "str" + } + ], + "checkall": "true", + "repair": false, + "outputs": 2, + "x": 650, + "y": 760, + "wires": [ + [ + "2b009bd7.c07004" + ], + [ + "3bbb756a.84190a" + ] + ] + }, + { + "id": "3bbb756a.84190a", + "type": "function", + "z": "baa1e3d9.cb29d", + "name": "set camera name", + "func": "global.set(\"acq_camera\", msg.payload.camera_name);\n\nmsg.payload = msg.payload.camera_name;\n\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 810, + "y": 780, + "wires": [ + [ + "559a8085.1d6b9" + ] + ] + }, + { + "id": "559a8085.1d6b9", + "type": "link out", + "z": "baa1e3d9.cb29d", + "name": "Camera Name", + "links": [ + "30067f35.532f2", + "572a6daa.6004c4", + "cfc783d7.d6ceb" + ], + "x": 965, + "y": 780, + "wires": [] + }, + { + "id": "49ea1123.ee1768", + "type": "ui_numeric", + "z": "baa1e3d9.cb29d", + "name": "sleep_before", + "label": "Delay to stabilize image (s)", + "tooltip": "Happens before every capture", + "group": "4322c187.e73e5", + "order": 4, + "width": 5, + "height": 1, + "wrap": false, + "passthru": true, + "topic": "sleep_before", + "topicType": "str", + "format": "{{value}}", + "min": "0.1", + "max": "5", + "step": "0.1", + "className": "", + "x": 670, + "y": 140, + "wires": [ + [ + "fb887036.12429" + ] + ] + }, + { + "id": "572a6daa.6004c4", + "type": "link in", + "z": "baa1e3d9.cb29d", + "name": "", + "links": [ + "559a8085.1d6b9" + ], + "x": 735, + "y": 60, + "wires": [ + [ + "99b11fe4.2795d" + ] + ] + }, + { + "id": "8032ea50.1b57f", + "type": "ui_template", + "z": "baa1e3d9.cb29d", + "group": "b5d61bc7.54fe48", + "name": "progress header", + "order": 1, + "width": 0, + "height": 0, + "format": "

Capture progress

", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "x": 1270, + "y": 820, + "wires": [ + [] + ] + }, + { + "id": "a4abb1ae.2ae418", + "type": "subflow:1c24ad9c.bebec2", + "z": "baa1e3d9.cb29d", + "name": "", + "env": [], + "x": 890, + "y": 480, + "wires": [ + [] + ] + }, + { + "id": "4be09c97f86897d9", + "type": "function", + "z": "baa1e3d9.cb29d", + "name": "get nb_frame", + "func": "msg.payload = msg.payload.nb_frame;\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 330, + "y": 220, + "wires": [ + [ + "51b4d0df.d70a88" + ] + ] + }, + { + "id": "f573206abefa9518", + "type": "function", + "z": "baa1e3d9.cb29d", + "name": "get imaging_pump_volume", + "func": "msg.payload = msg.payload.imaging_pump_volume;\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 380, + "y": 260, + "wires": [ + [ + "0df8d1d86af6455a" + ] + ] + }, + { + "id": "f948151ab4031df4", + "type": "function", + "z": "baa1e3d9.cb29d", + "name": "get sleep_before", + "func": "msg.payload = msg.payload.sleep_before;\nreturn msg;", + "outputs": 1, + "timeout": "", + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 340, + "y": 140, + "wires": [ + [ + "49ea1123.ee1768" + ] + ] + }, + { + "id": "ad153212312f0347", + "type": "ui_ui_control", + "z": "baa1e3d9.cb29d", + "name": "onTab", + "events": "all", + "x": 310, + "y": 340, + "wires": [ + [ + "9b69ea945b587192" + ] + ] + }, + { + "id": "9b69ea945b587192", + "type": "function", + "z": "baa1e3d9.cb29d", + "name": "check tab", + "func": "if (msg.name == \"Fluidic Acquisition\"){\n return { \"topic\": \"imager/ image\" }\n}", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 460, + "y": 340, + "wires": [ + [ + "52ea7d01.711034" + ] + ], + "outputLabels": [ + "interface" + ] + }, + { + "id": "0df8d1d86af6455a", + "type": "ui_text_input", + "z": "baa1e3d9.cb29d", + "name": "imaging_pump_volume", + "label": "Pumped volume (mL)", + "tooltip": "between frames", + "group": "4322c187.e73e5", + "order": 3, + "width": 0, + "height": 0, + "passthru": true, + "mode": "number", + "delay": 300, + "topic": "imaging_pump_volume", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 630, + "y": 260, + "wires": [ + [ + "fb887036.12429", + "67091ac0.8f9f6c" + ] + ] + }, + { + "id": "9d6abe67.6bb3d", + "type": "ui_button", + "z": "cb95299c.2817c8", + "name": "", + "group": "64903b47.4034e4", + "order": 1, + "width": 0, + "height": 0, + "passthru": false, + "label": "Home", + "tooltip": "", + "color": "", + "bgcolor": "", + "icon": "home", + "payload": "{\"tab\":\"Home\"}", + "payloadType": "json", + "topic": "", + "x": 430, + "y": 600, + "wires": [ + [ + "f0fb77cf.8f1c28" + ] + ] + }, + { + "id": "f0fb77cf.8f1c28", + "type": "ui_ui_control", + "z": "cb95299c.2817c8", + "name": "", + "events": "change", + "x": 740, + "y": 600, + "wires": [ + [] + ] + }, + { + "id": "8ec68b82.17e3d8", + "type": "ui_button", + "z": "cb95299c.2817c8", + "name": "Start segmentation", + "group": "abeb6dad.635a2", + "order": 10, + "width": 5, + "height": 1, + "passthru": false, + "label": "Start segmentation", + "tooltip": "", + "color": "", + "bgcolor": "", + "icon": "", + "payload": "{\"action\":\"segment\"}", + "payloadType": "json", + "topic": "segmenter/segment", + "x": 370, + "y": 460, + "wires": [ + [ + "33c28dc1.238002", + "c72a1064.1ec388" + ] + ] + }, + { + "id": "27be7971.b3fbce", + "type": "ui_button", + "z": "cb95299c.2817c8", + "d": true, + "name": "Stop segmentation", + "group": "abeb6dad.635a2", + "order": 12, + "width": 4, + "height": 1, + "passthru": true, + "label": "Stop segmentation", + "tooltip": "", + "color": "", + "bgcolor": "#AD1625", + "icon": "", + "payload": "{\"action\":\"stop\"}", + "payloadType": "json", + "topic": "segmenter/segment", + "x": 370, + "y": 520, + "wires": [ + [ + "16f3cef4.0acac9" + ] + ] + }, + { + "id": "16f3cef4.0acac9", + "type": "mqtt out", + "z": "cb95299c.2817c8", + "name": "", + "topic": "", + "qos": "", + "retain": "", + "broker": "8dc3722c.06efa8", + "x": 850, + "y": 520, + "wires": [] + }, + { + "id": "8f3788f6.ddcf98", + "type": "function", + "z": "cb95299c.2817c8", + "name": "obj_counter", + "func": "obj_counter = flow.get('obj_counter')\nobj_counter = obj_counter + 1\nflow.set('obj_counter', obj_counter)\nmsg.payload = obj_counter\nmsg.topic = \"object count\"\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 810, + "y": 800, + "wires": [ + [ + "fa3b7929.ac7da8", + "9d53dbe2.dbffe8" + ] + ] + }, + { + "id": "aa38dbbc.cf0a9", + "type": "switch", + "z": "cb95299c.2817c8", + "name": "Segmenter", + "property": "topic", + "propertyType": "msg", + "rules": [ + { + "t": "eq", + "v": "status/segmenter", + "vt": "str" + }, + { + "t": "eq", + "v": "status/segmenter/name", + "vt": "str" + }, + { + "t": "eq", + "v": "status/segmenter/object_id", + "vt": "str" + }, + { + "t": "eq", + "v": "status/segmenter/metric", + "vt": "str" + } + ], + "checkall": "true", + "repair": false, + "outputs": 4, + "x": 490, + "y": 740, + "wires": [ + [ + "b9a23b91.93638", + "6919465f.332e5" + ], + [ + "49af3d24.1799e4" + ], + [ + "8f3788f6.ddcf98" + ], + [ + "50ce901f.b5034" + ] + ] + }, + { + "id": "9d53dbe2.dbffe8", + "type": "ui_chart", + "z": "cb95299c.2817c8", + "name": "counter graph", + "group": "46be9c86.dea684", + "order": 7, + "width": 10, + "height": 2, + "label": "", + "chartType": "horizontalBar", + "legend": "false", + "xformat": "HH:mm:ss", + "interpolate": "linear", + "nodata": "Objects count will be shown here once the segmentation is started", + "dot": false, + "ymin": "", + "ymax": "", + "removeOlder": 1, + "removeOlderPoints": "", + "removeOlderUnit": "3600", + "cutout": 0, + "useOneColor": true, + "useUTC": false, + "colors": [ + "#1f77b4", + "#aec7e8", + "#ff7f0e", + "#2ca02c", + "#98df8a", + "#d62728", + "#ff9896", + "#9467bd", + "#c5b0d5" + ], + "outputs": 1, + "x": 1340, + "y": 840, + "wires": [ + [] + ] + }, + { + "id": "50ce901f.b5034", + "type": "function", + "z": "cb95299c.2817c8", + "name": "ex : area", + "func": "// Payload looks like this:\n// {'name': '01_13_28_232066_0',\n// 'metadata': {\n// 'label': 0, 'width': 29, 'height': 80, ....\n\nmsg.payload=msg.payload.metadata.area_exc\nmsg.topic=\"area\"\n\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 800, + "y": 920, + "wires": [ + [ + "458cd82e.03d258" + ] + ] + }, + { + "id": "a4f0f0d1.3aca88", + "type": "ui_toast", + "z": "cb95299c.2817c8", + "position": "top right", + "displayTime": "5", + "highlight": "", + "sendall": true, + "outputs": 0, + "ok": "OK", + "cancel": "", + "raw": false, + "topic": "", + "name": "", + "x": 1350, + "y": 680, + "wires": [] + }, + { + "id": "458cd82e.03d258", + "type": "ui_chart", + "z": "cb95299c.2817c8", + "name": "Area chart", + "group": "46be9c86.dea684", + "order": 9, + "width": 10, + "height": 6, + "label": "", + "chartType": "line", + "legend": "false", + "xformat": "HH:mm:ss", + "interpolate": "linear", + "nodata": "Objects area will be shown here once the segmentation is started", + "dot": true, + "ymin": "", + "ymax": "", + "removeOlder": 1, + "removeOlderPoints": "1000", + "removeOlderUnit": "3600", + "cutout": 0, + "useOneColor": false, + "useUTC": true, + "colors": [ + "#1f77b4", + "#aec7e8", + "#ff7f0e", + "#2ca02c", + "#98df8a", + "#d62728", + "#ff9896", + "#9467bd", + "#c5b0d5" + ], + "outputs": 1, + "x": 1330, + "y": 920, + "wires": [ + [] + ] + }, + { + "id": "49af3d24.1799e4", + "type": "debug", + "z": "cb95299c.2817c8", + "name": "segmentation name", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 840, + "y": 760, + "wires": [] + }, + { + "id": "7088a5be.0c79a4", + "type": "template", + "z": "cb95299c.2817c8", + "name": "Create sentence", + "field": "payload", + "fieldType": "msg", + "format": "handlebars", + "syntax": "mustache", + "template": "The {{topic}} is {{payload.status}}", + "output": "str", + "x": 1100, + "y": 680, + "wires": [ + [ + "a4f0f0d1.3aca88" + ] + ] + }, + { + "id": "b9a23b91.93638", + "type": "change", + "z": "cb95299c.2817c8", + "name": "Remove high-level topic", + "rules": [ + { + "t": "change", + "p": "topic", + "pt": "msg", + "from": "status/", + "fromt": "str", + "to": "", + "tot": "str" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 850, + "y": 680, + "wires": [ + [ + "7088a5be.0c79a4" + ] + ] + }, + { + "id": "6919465f.332e5", + "type": "ui_text", + "z": "cb95299c.2817c8", + "group": "46be9c86.dea684", + "order": 1, + "width": 10, + "height": 1, + "name": "segmenter", + "label": "Segmenter status:", + "format": "{{msg.payload.status}}", + "layout": "row-spread", + "x": 810, + "y": 720, + "wires": [] + }, + { + "id": "fa3b7929.ac7da8", + "type": "ui_text", + "z": "cb95299c.2817c8", + "group": "46be9c86.dea684", + "order": 5, + "width": 4, + "height": 1, + "name": "counter", + "label": "", + "format": "{{msg.payload}}", + "layout": "col-center", + "x": 1320, + "y": 800, + "wires": [] + }, + { + "id": "640ece83.88cab", + "type": "inject", + "z": "cb95299c.2817c8", + "name": "Init graphs", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": 0.1, + "topic": "object count", + "payload": "0", + "payloadType": "num", + "x": 810, + "y": 880, + "wires": [ + [ + "ac439738.28bc18", + "4f3f7c4a.cb21c4" + ] + ] + }, + { + "id": "25867454.a8e334", + "type": "link in", + "z": "cb95299c.2817c8", + "name": "Segmenter module status", + "links": [ + "dcf5bd45.16a8d" + ], + "x": 295, + "y": 740, + "wires": [ + [ + "aa38dbbc.cf0a9" + ] + ] + }, + { + "id": "c8749cbb.55254", + "type": "function", + "z": "cb95299c.2817c8", + "name": "set global", + "func": "global.set(msg.topic, msg.payload);", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 960, + "y": 380, + "wires": [ + [] + ] + }, + { + "id": "d43c3ed9.e6cb1", + "type": "ui_template", + "z": "cb95299c.2817c8", + "group": "46be9c86.dea684", + "name": "Object counts", + "order": 3, + "width": 0, + "height": 0, + "format": "

Object counts

", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "x": 1340, + "y": 760, + "wires": [ + [] + ] + }, + { + "id": "857e90c1.cd25b", + "type": "ui_template", + "z": "cb95299c.2817c8", + "group": "46be9c86.dea684", + "name": "Area chart", + "order": 8, + "width": 0, + "height": 0, + "format": "

Area chart

", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "x": 1330, + "y": 880, + "wires": [ + [] + ] + }, + { + "id": "33c28dc1.238002", + "type": "function", + "z": "cb95299c.2817c8", + "name": "prepare segmentation", + "func": "global.set('obj_counter', 0);\n\nvar segmentation_list = flow.get('segmentation_list')\nif (segmentation_list !== undefined && segmentation_list !== \"\") {\n msg.payload['path'] = segmentation_list\n}\n\n\nvar force = flow.get('force')\nif (force !== undefined && force !== \"\") {\n msg.payload['settings'] = {\"force\":Boolean(force)}\n}\n\n\nvar recursive = flow.get('recursive')\nif (recursive !== undefined && recursive !== \"\") {\n if (\"settings\" in msg.payload){\n msg.payload.settings[\"recursive\"] = Boolean(recursive)\n }\n else{\n msg.payload['settings'] = {\"recursive\": Boolean(recursive)}\n }\n}\n\nvar ecotaxa = flow.get('ecotaxa')\nif (ecotaxa !== undefined && ecotaxa !== \"\") {\n if (\"settings\" in msg.payload){\n msg.payload.settings[\"ecotaxa\"] = Boolean(ecotaxa)\n }\n else{\n msg.payload['settings'] = {\"ecotaxa\": Boolean(ecotaxa)}\n }\n}\n\nvar keep = flow.get('keep')\nif (keep !== undefined && keep !== \"\") {\n if (\"settings\" in msg.payload){\n msg.payload.settings[\"keep\"] = Boolean(keep)\n }\n else{\n msg.payload['settings'] = {\"keep\": Boolean(keep)}\n }\n}\n\nvar process_id = global.get('process_id')\nif (process_id !== undefined && process_id !== \"\") {\n if (\"settings\" in msg.payload){\n msg.payload.settings[\"process_id\"] = process_id\n }\n else{\n msg.payload['settings'] = {\"process_id\": process_id}\n }\n}\n\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 460, + "wires": [ + [ + "16f3cef4.0acac9" + ] + ] + }, + { + "id": "fa12f9f8.00cfa8", + "type": "subflow:1c24ad9c.bebec2", + "z": "cb95299c.2817c8", + "name": "", + "env": [], + "x": 430, + "y": 380, + "wires": [ + [ + "3b72d11c.86e9e6" + ] + ] + }, + { + "id": "3b72d11c.86e9e6", + "type": "function", + "z": "cb95299c.2817c8", + "name": "get process_id", + "func": "msg.payload = msg.payload.process_id;\nmsg.topic = \"process_id\";\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 600, + "y": 380, + "wires": [ + [ + "56971109c8be3b54" + ] + ] + }, + { + "id": "3ea12061.ce62c", + "type": "ui_list", + "z": "cb95299c.2817c8", + "group": "abeb6dad.635a2", + "name": "", + "order": 9, + "width": 10, + "height": 11, + "lineType": "one", + "actionType": "check", + "allowHTML": false, + "outputs": 1, + "topic": "", + "x": 770, + "y": 140, + "wires": [ + [ + "cb3b87b5.63c4" + ] + ] + }, + { + "id": "8bd8fb2c.53fa4", + "type": "dir2files", + "z": "cb95299c.2817c8", + "name": "", + "dirname": "/home/pi/data/img/", + "pathRegex": "", + "isRecursive": true, + "findDir": true, + "isArray": true, + "x": 460, + "y": 140, + "wires": [ + [ + "ba2947.c854deb8" + ] + ] + }, + { + "id": "127d4ee.f8ad1b1", + "type": "ui_button", + "z": "cb95299c.2817c8", + "name": "Refresh", + "group": "abeb6dad.635a2", + "order": 8, + "width": 0, + "height": 0, + "passthru": false, + "label": "Update acquisition's folder list", + "tooltip": "Refresh the list of previous acquisitions", + "color": "", + "bgcolor": "", + "icon": "mi-find_replace", + "payload": "", + "payloadType": "date", + "topic": "update", + "x": 260, + "y": 140, + "wires": [ + [ + "8bd8fb2c.53fa4", + "56f845f5.e7c054" + ] + ] + }, + { + "id": "946ce9ee.092cf", + "type": "inject", + "z": "cb95299c.2817c8", + "name": "Init", + "props": [ + { + "p": "payload" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 270, + "y": 100, + "wires": [ + [ + "8bd8fb2c.53fa4", + "56f845f5.e7c054" + ] + ] + }, + { + "id": "cb3b87b5.63c4", + "type": "function", + "z": "cb95299c.2817c8", + "name": "update segmentation_list", + "func": "var segmentation_list = flow.get('segmentation_list');\n\nif (segmentation_list === undefined || segmentation_list === \"\") {\n segmentation_list = []\n console.log(\"error\")\n}\n\npath = \"/home/pi/data/img/\" + msg.payload.title\n\nif (msg.payload.isChecked){\n if (segmentation_list.includes(path) === false){\n segmentation_list.push(path)\n }\n // Element already in list, don't push it more than once\n //segmentation_list.push(msg.payload[\"title\"])\n}\nelse {\n var pos = segmentation_list.indexOf(path)\n segmentation_list.splice(pos, 1)\n}\n\nflow.set('segmentation_list', segmentation_list)", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 950, + "y": 140, + "wires": [ + [] + ] + }, + { + "id": "56f845f5.e7c054", + "type": "change", + "z": "cb95299c.2817c8", + "name": "Reset segmentation_list", + "rules": [ + { + "t": "set", + "p": "segmentation_list", + "pt": "flow", + "to": "[]", + "tot": "json" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 510, + "y": 100, + "wires": [ + [] + ] + }, + { + "id": "7fc72364.8f038c", + "type": "ui_template", + "z": "cb95299c.2817c8", + "group": "abeb6dad.635a2", + "name": "Update message", + "order": 1, + "width": 10, + "height": 3, + "format": "
You can choose here in which folder(s) you want the segmentation script to run. A few details though:\n
The segmentation is run recursively in all folders. So if you select a top level folder, the segmentation will be run in all subfolders.\n
Also, you will be able to chose wether for force the segmentation for folders in which it has run already.
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "x": 270, + "y": 40, + "wires": [ + [] + ] + }, + { + "id": "ba2947.c854deb8", + "type": "function", + "z": "cb95299c.2817c8", + "name": "remove common", + "func": "function remove_path(item, index, array) {\n array[index] = item.replace(\"/home/pi/data/img/\", \"\")\n} \n\nmsg.payload.forEach(remove_path)\n\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 620, + "y": 140, + "wires": [ + [ + "3ea12061.ce62c" + ] + ] + }, + { + "id": "21af0db1.c2c182", + "type": "ui_multistate_switch", + "z": "cb95299c.2817c8", + "name": "recursive toggle", + "group": "abeb6dad.635a2", + "order": 4, + "width": 5, + "height": 1, + "label": "Recursive folder", + "stateField": "payload", + "enableField": "enable", + "rounded": true, + "useThemeColors": true, + "hideSelectedLabel": false, + "options": [ + { + "label": "No", + "value": "0", + "valueType": "num", + "color": "#009933" + }, + { + "label": "Yes", + "value": "1", + "valueType": "num", + "color": "#999999" + } + ], + "x": 480, + "y": 220, + "wires": [ + [ + "880b192a.88e2d" + ] + ] + }, + { + "id": "dffb9881.feef8", + "type": "ui_multistate_switch", + "z": "cb95299c.2817c8", + "name": "force toggle", + "group": "abeb6dad.635a2", + "order": 3, + "width": 5, + "height": 1, + "label": "Force rework", + "stateField": "payload", + "enableField": "enable", + "rounded": true, + "useThemeColors": true, + "hideSelectedLabel": false, + "options": [ + { + "label": "No", + "value": "0", + "valueType": "num", + "color": "#009933" + }, + { + "label": "Yes", + "value": "1", + "valueType": "num", + "color": "#999999" + } + ], + "x": 470, + "y": 300, + "wires": [ + [ + "a4f68fa6.5d77f8" + ] + ] + }, + { + "id": "880b192a.88e2d", + "type": "change", + "z": "cb95299c.2817c8", + "name": "", + "rules": [ + { + "t": "set", + "p": "recursive", + "pt": "flow", + "to": "payload", + "tot": "msg" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 690, + "y": 240, + "wires": [ + [] + ] + }, + { + "id": "a4f68fa6.5d77f8", + "type": "change", + "z": "cb95299c.2817c8", + "name": "", + "rules": [ + { + "t": "set", + "p": "force", + "pt": "flow", + "to": "payload", + "tot": "msg" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 670, + "y": 280, + "wires": [ + [] + ] + }, + { + "id": "1ef1b43b.b0f064", + "type": "inject", + "z": "cb95299c.2817c8", + "name": "0", + "props": [ + { + "p": "payload" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": 0.1, + "topic": "", + "payload": "0", + "payloadType": "num", + "x": 270, + "y": 280, + "wires": [ + [ + "dffb9881.feef8", + "a4f68fa6.5d77f8" + ] + ] + }, + { + "id": "f078c068.eacf58", + "type": "ui_template", + "z": "cb95299c.2817c8", + "group": "46be9c86.dea684", + "name": "Stream Segmented object", + "order": 2, + "width": 10, + "height": 8, + "format": "
\n Latest object segmented:
\n \"If\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 1380, + "y": 600, + "wires": [ + [] + ] + }, + { + "id": "43f97b93.b76294", + "type": "inject", + "z": "cb95299c.2817c8", + "name": "1", + "props": [ + { + "p": "payload" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": 0.1, + "topic": "", + "payload": "1", + "payloadType": "num", + "x": 270, + "y": 240, + "wires": [ + [ + "21af0db1.c2c182", + "880b192a.88e2d" + ] + ] + }, + { + "id": "ac439738.28bc18", + "type": "function", + "z": "cb95299c.2817c8", + "name": "chart init", + "func": "obj=[{\"series\": [],\"data\": [],\"labels\": []}]\nmsg.payload = obj\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 980, + "y": 880, + "wires": [ + [ + "458cd82e.03d258" + ] + ] + }, + { + "id": "4f3f7c4a.cb21c4", + "type": "change", + "z": "cb95299c.2817c8", + "name": "", + "rules": [ + { + "t": "set", + "p": "obj_counter", + "pt": "flow", + "to": "0", + "tot": "num" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 1020, + "y": 840, + "wires": [ + [ + "fa3b7929.ac7da8", + "9d53dbe2.dbffe8" + ] + ] + }, + { + "id": "6bce0f60.f48998", + "type": "link in", + "z": "cb95299c.2817c8", + "name": "", + "links": [ + "596fc9d4.46c75" + ], + "x": 855, + "y": 840, + "wires": [ + [ + "4f3f7c4a.cb21c4", + "ac439738.28bc18" + ] + ] + }, + { + "id": "596fc9d4.46c75", + "type": "link out", + "z": "cb95299c.2817c8", + "name": "", + "links": [ + "6bce0f60.f48998" + ], + "x": 715, + "y": 500, + "wires": [] + }, + { + "id": "c72a1064.1ec388", + "type": "change", + "z": "cb95299c.2817c8", + "name": "Reset counters", + "rules": [ + { + "t": "set", + "p": "topic", + "pt": "msg", + "to": "object count", + "tot": "str" + }, + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "0", + "tot": "num" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 600, + "y": 500, + "wires": [ + [ + "596fc9d4.46c75" + ] + ] + }, + { + "id": "9367534a.fb8568", + "type": "ui_multistate_switch", + "z": "cb95299c.2817c8", + "name": "Ecotaxa archive", + "group": "abeb6dad.635a2", + "order": 6, + "width": 5, + "height": 1, + "label": "Ecotaxa archive", + "stateField": "payload", + "enableField": "enable", + "rounded": true, + "useThemeColors": true, + "hideSelectedLabel": false, + "options": [ + { + "label": "No", + "value": "0", + "valueType": "num", + "color": "#009933" + }, + { + "label": "Yes", + "value": "1", + "valueType": "num", + "color": "#999999" + } + ], + "x": 1080, + "y": 220, + "wires": [ + [ + "25ac4f9a.5b05c8" + ] + ] + }, + { + "id": "25ac4f9a.5b05c8", + "type": "change", + "z": "cb95299c.2817c8", + "name": "", + "rules": [ + { + "t": "set", + "p": "ecotaxa", + "pt": "flow", + "to": "payload", + "tot": "msg" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 1280, + "y": 240, + "wires": [ + [] + ] + }, + { + "id": "bef78886.8f0b98", + "type": "inject", + "z": "cb95299c.2817c8", + "name": "1", + "props": [ + { + "p": "payload" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": 0.1, + "topic": "", + "payload": "1", + "payloadType": "num", + "x": 910, + "y": 240, + "wires": [ + [ + "9367534a.fb8568", + "25ac4f9a.5b05c8" + ] + ] + }, + { + "id": "32465a4e.8fcac6", + "type": "ui_multistate_switch", + "z": "cb95299c.2817c8", + "name": "Keep objects", + "group": "abeb6dad.635a2", + "order": 5, + "width": 5, + "height": 1, + "label": "Keep objects", + "stateField": "payload", + "enableField": "enable", + "rounded": true, + "useThemeColors": true, + "hideSelectedLabel": false, + "options": [ + { + "label": "No", + "value": "0", + "valueType": "num", + "color": "#009933" + }, + { + "label": "Yes", + "value": "1", + "valueType": "num", + "color": "#999999" + } + ], + "x": 1070, + "y": 300, + "wires": [ + [ + "8dd6f57f.b77f98" + ] + ] + }, + { + "id": "8dd6f57f.b77f98", + "type": "change", + "z": "cb95299c.2817c8", + "name": "", + "rules": [ + { + "t": "set", + "p": "keep", + "pt": "flow", + "to": "payload", + "tot": "msg" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 1270, + "y": 280, + "wires": [ + [] + ] + }, + { + "id": "8090df89.c029e", + "type": "inject", + "z": "cb95299c.2817c8", + "name": "1", + "props": [ + { + "p": "payload" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": 0.1, + "topic": "", + "payload": "1", + "payloadType": "num", + "x": 910, + "y": 280, + "wires": [ + [ + "32465a4e.8fcac6", + "8dd6f57f.b77f98" + ] + ] + }, + { + "id": "56971109c8be3b54", + "type": "ui_text_input", + "z": "cb95299c.2817c8", + "name": "process_id", + "label": "Process unique ID*", + "tooltip": "", + "group": "abeb6dad.635a2", + "order": 2, + "width": 10, + "height": 1, + "passthru": true, + "mode": "text", + "delay": 300, + "topic": "process_id", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 790, + "y": 380, + "wires": [ + [ + "c8749cbb.55254" + ] + ] + }, + { + "id": "2911fbc6.d28c24", + "type": "ui_template", + "z": "c1660bc.e7ff7f8", + "group": "c0ebfc57.42527", + "name": "Image browser", + "order": 1, + "width": "0", + "height": "0", + "format": "
\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 400, + "y": 100, + "wires": [ + [] + ] + }, + { + "id": "4f02c726.de69b8", + "type": "ui_button", + "z": "9daf9e2b.019fc", + "name": "", + "group": "a7d64879.38298", + "order": 4, + "width": "6", + "height": 1, + "passthru": false, + "label": "Reboot", + "tooltip": "", + "color": "", + "bgcolor": "#AD1625", + "className": "", + "icon": "fa-repeat fa-2x", + "payload": "reboot", + "payloadType": "str", + "topic": "reboot", + "topicType": "str", + "x": 160, + "y": 240, + "wires": [ + [ + "611a8b1c.a829b4" + ] + ] + }, + { + "id": "611a8b1c.a829b4", + "type": "exec", + "z": "9daf9e2b.019fc", + "command": "sudo", + "addpay": "payload", + "append": "now", + "useSpawn": "false", + "timer": "2", + "winHide": false, + "oldrc": false, + "name": "sudo cmd now", + "x": 480, + "y": 280, + "wires": [ + [], + [], + [] + ] + }, + { + "id": "bc76c4d6.a7ad28", + "type": "ui_button", + "z": "9daf9e2b.019fc", + "name": "", + "group": "a7d64879.38298", + "order": 5, + "width": "6", + "height": 1, + "passthru": false, + "label": "Shutdown", + "tooltip": "", + "color": "", + "bgcolor": "#AD1625", + "className": "", + "icon": "fa-power-off fa-2x", + "payload": "shutdown", + "payloadType": "str", + "topic": "shutdown", + "topicType": "str", + "x": 160, + "y": 320, + "wires": [ + [ + "611a8b1c.a829b4" + ] + ] + }, + { + "id": "d12008a0.47be4", + "type": "ui_template", + "z": "9daf9e2b.019fc", + "group": "1be83144.4fe4bf", + "name": "Node-RED Log table", + "order": 1, + "width": 12, + "height": 10, + "format": "\n\n

\n Note: this panel only shows certain errors generated within the Node-RED dashboard. Actual logs should be instead accessed from the \"Logs\" panel on this page.\n

\n\n\n Copy Log\n\n\n\n \n \n \n
{{row}}
\n\n", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 820, + "y": 620, + "wires": [ + [] + ] + }, + { + "id": "8b511c2b.9c24c8", + "type": "function", + "z": "9daf9e2b.019fc", + "name": "Log array", + "func": "var log = flow.get(\"nodered_log\")||[];\n\nlog = log.concat(msg.payload.trim().split('\\n'));\n\nwhile (log.length > 500){\n log.shift();\n}\n\nflow.set(\"nodered_log\", log);\n\nmsg.payload = log;\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 580, + "wires": [ + [ + "d12008a0.47be4" + ] + ] + }, + { + "id": "7a1dedf.1c63094", + "type": "ui_button", + "z": "9daf9e2b.019fc", + "name": "Clear Node-RED Log", + "group": "1be83144.4fe4bf", + "order": 2, + "width": 0, + "height": 0, + "passthru": true, + "label": "Clear Log", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "fa-eraser", + "payload": "", + "payloadType": "str", + "topic": "", + "topicType": "str", + "x": 340, + "y": 660, + "wires": [ + [ + "73500be7.9ab7c4" + ] + ] + }, + { + "id": "9187bf97.9922b8", + "type": "catch", + "z": "9daf9e2b.019fc", + "name": "Catch Errors", + "scope": null, + "uncaught": false, + "x": 150, + "y": 580, + "wires": [ + [ + "f9a871d5.a73828" + ] + ] + }, + { + "id": "f9a871d5.a73828", + "type": "function", + "z": "9daf9e2b.019fc", + "name": "Get error", + "func": "msg.payload = \"Node Red Error: \" + msg.error + \" created by the message \" + msg.payload;\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 420, + "y": 580, + "wires": [ + [ + "8b511c2b.9c24c8" + ] + ] + }, + { + "id": "73500be7.9ab7c4", + "type": "function", + "z": "9daf9e2b.019fc", + "name": "Clear Node-RED log", + "func": "flow.set(\"nodered_log\", [\"Log cleared!\"]);\n\nmsg.payload = [\"Log cleared!\"];\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 580, + "y": 660, + "wires": [ + [ + "d12008a0.47be4" + ] + ] + }, + { + "id": "50f9b5b.a84bccc", + "type": "inject", + "z": "9daf9e2b.019fc", + "name": "Default: ON", + "props": [ + { + "p": "payload" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "0.01", + "topic": "", + "payload": "true", + "payloadType": "bool", + "x": 150, + "y": 100, + "wires": [ + [ + "ae3c28d0ec056b4a", + "81b84006deb8bda6", + "f6d2cd9f04d5b7ba", + "312003ed9b9014ab" + ] + ] + }, + { + "id": "f4f6e3fa.0234f", + "type": "inject", + "z": "9daf9e2b.019fc", + "name": "once", + "props": [ + { + "p": "payload" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "", + "topic": "", + "payload": "start", + "payloadType": "str", + "x": 170, + "y": 660, + "wires": [ + [ + "7a1dedf.1c63094" + ] + ] + }, + { + "id": "b81b990a.d4dca", + "type": "link in", + "z": "9daf9e2b.019fc", + "name": "Shutdown", + "links": [ + "e08cfcb8.2a67e8" + ], + "x": 195, + "y": 280, + "wires": [ + [ + "611a8b1c.a829b4" + ] + ] + }, + { + "id": "81b84006deb8bda6", + "type": "rpi-gpio out", + "z": "9daf9e2b.019fc", + "name": "Pump Enable", + "pin": "4", + "set": true, + "level": "1", + "freq": "", + "out": "out", + "bcm": true, + "x": 400, + "y": 80, + "wires": [] + }, + { + "id": "f6d2cd9f04d5b7ba", + "type": "rpi-gpio out", + "z": "9daf9e2b.019fc", + "name": "Focus Enable", + "pin": "12", + "set": true, + "level": "1", + "freq": "", + "out": "out", + "bcm": true, + "x": 400, + "y": 120, + "wires": [] + }, + { + "id": "ae3c28d0ec056b4a", + "type": "rpi-gpio out", + "z": "9daf9e2b.019fc", + "name": "HAT Pump Enable", + "pin": "23", + "set": true, + "level": "1", + "freq": "", + "out": "out", + "bcm": true, + "x": 410, + "y": 40, + "wires": [] + }, + { + "id": "312003ed9b9014ab", + "type": "rpi-gpio out", + "z": "9daf9e2b.019fc", + "name": "HAT Focus Enable", + "pin": "5", + "set": true, + "level": "1", + "freq": "", + "out": "out", + "bcm": true, + "x": 410, + "y": 160, + "wires": [] + }, + { + "id": "ea4fae012404854c", + "type": "ui_button", + "z": "9daf9e2b.019fc", + "name": "", + "group": "a7d64879.38298", + "order": 2, + "width": "6", + "height": 1, + "passthru": true, + "label": "Restart Hardware Controller", + "tooltip": "", + "color": "", + "bgcolor": "#AD1625", + "className": "", + "icon": "fa-refresh fa-2x", + "payload": "Restarting hardware controller...", + "payloadType": "str", + "topic": "", + "topicType": "str", + "x": 440, + "y": 420, + "wires": [ + [ + "c54d948575dbcff8", + "d10f3ffd98055447" + ] + ] + }, + { + "id": "438febd245a9f73c", + "type": "link in", + "z": "9daf9e2b.019fc", + "name": "Restart Hardware Controller", + "links": [ + "e41870d7.300eb8" + ], + "x": 195, + "y": 420, + "wires": [ + [ + "ea4fae012404854c" + ] + ] + }, + { + "id": "c54d948575dbcff8", + "type": "exec", + "z": "9daf9e2b.019fc", + "command": "sudo systemctl restart planktoscope-org.device-backend.controller-pscopehat.service", + "addpay": false, + "append": "", + "useSpawn": "false", + "timer": "", + "winHide": false, + "oldrc": false, + "name": "Restart hardware controller", + "x": 780, + "y": 420, + "wires": [ + [], + [], + [] + ] + }, + { + "id": "e2e5ce0351a6cc11", + "type": "ui_button", + "z": "9daf9e2b.019fc", + "name": "", + "group": "a7d64879.38298", + "order": 3, + "width": "6", + "height": 1, + "passthru": true, + "label": "Restart Segmenter", + "tooltip": "", + "color": "", + "bgcolor": "#AD1625", + "className": "", + "icon": "fa-refresh fa-2x", + "payload": "Restarting segmenter...", + "payloadType": "str", + "topic": "", + "topicType": "str", + "x": 410, + "y": 500, + "wires": [ + [ + "2cdbadb65d0e1b20", + "9c1629488b02fdba" + ] + ] + }, + { + "id": "2cdbadb65d0e1b20", + "type": "exec", + "z": "9daf9e2b.019fc", + "command": "sudo systemctl restart planktoscope-org.device-backend.processing.segmenter.service", + "addpay": false, + "append": "", + "useSpawn": "false", + "timer": "", + "winHide": false, + "oldrc": false, + "name": "Restart segmenter", + "x": 750, + "y": 500, + "wires": [ + [], + [], + [] + ] + }, + { + "id": "7b64209d734e4e2c", + "type": "ui_template", + "z": "9daf9e2b.019fc", + "group": "a7d64879.38298", + "name": "Logs", + "order": 1, + "width": "0", + "height": "0", + "format": "

\n The PlanktoScope software application consists of three components: a Node-RED dashboard which provides the user interface you're using; a Hardware Controller\n which executes commands sent from the Node-RED dashboard for hardware control and image acquisition; and a Segmenter which processes an acquired dataset of\n images and isolates objects from those images. Each component has its own independent log of messages, managed separately from the logs for the other components.\n

\n

\n All three components have live-updating logs which you can monitor. Additionally, the Hardware Controller and the Segmenter also save all of their log messages\n to files which you can browse and download. Those software components create a new log file each time they start, and the name of the log file includes the time\n in the PlanktoScope's clock when the software component started. However, if your PlanktoScope's clock is usually wrong, it makes the log files difficult to navigate.\n This will be fixed in a future version of the software.\n

\n

\n If you need to share your logs with other people (e.g. on Slack or GitHub), you should open the \"Downloadable Logs\" links, and then you can select one file or multiple\n log files for downloading as a zip archive.\n

\n", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 630, + "y": 180, + "wires": [ + [] + ] + }, + { + "id": "d10f3ffd98055447", + "type": "ui_toast", + "z": "9daf9e2b.019fc", + "position": "top right", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 0, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 750, + "y": 380, + "wires": [] + }, + { + "id": "9c1629488b02fdba", + "type": "ui_toast", + "z": "9daf9e2b.019fc", + "position": "top right", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 0, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 750, + "y": 460, + "wires": [] + }, + { + "id": "ddcbbfa5.cd158", + "type": "exec", + "z": "1371dec5.76e671", + "command": "vcgencmd measure_temp | tr -d \"temp=\" | tr -d \"'C\" | tr -d \"\\n\"", + "addpay": false, + "append": "", + "useSpawn": "", + "timer": "", + "name": "RPi Temp.", + "x": 330, + "y": 40, + "wires": [ + [ + "bc503fa5.f46dd" + ], + [], + [] + ] + }, + { + "id": "3910d662.fa1f7a", + "type": "exec", + "z": "1371dec5.76e671", + "command": "df -h | grep /dev/root | awk -F ' ' '{print $5}' | tr -d % | tr \"\\n$\" \"\\ \" | sed 's/,/./' | tr -d \" \"", + "addpay": false, + "append": "", + "useSpawn": "", + "timer": "", + "name": "Disk Usage", + "x": 330, + "y": 120, + "wires": [ + [ + "eaf74a43.fa27d" + ], + [], + [] + ] + }, + { + "id": "1cd5b4c0.46af9b", + "type": "inject", + "z": "1371dec5.76e671", + "name": "update: 5s", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "5", + "crontab": "", + "once": false, + "onceDelay": "", + "topic": "", + "payload": "", + "payloadType": "date", + "x": 110, + "y": 160, + "wires": [ + [ + "3910d662.fa1f7a", + "ddcbbfa5.cd158", + "aa2e4cd182dbc776", + "797675a937dc1629", + "f6f570b10c675854" + ] + ] + }, + { + "id": "8485d05.444903", + "type": "ui_switch", + "z": "1371dec5.76e671", + "name": "fan_state", + "label": "Fan", + "tooltip": "Fan control", + "group": "3ca00bf9.e5cac4", + "order": 2, + "width": 2, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "", + "topicType": "str", + "style": "", + "onvalue": "100", + "onvalueType": "num", + "onicon": "", + "oncolor": "", + "offvalue": "20", + "offvalueType": "num", + "officon": "", + "offcolor": "", + "animate": true, + "x": 940, + "y": 40, + "wires": [ + [ + "952db22920d7d5f1" + ] + ] + }, + { + "id": "bc503fa5.f46dd", + "type": "switch", + "z": "1371dec5.76e671", + "name": "", + "property": "payload", + "propertyType": "msg", + "rules": [ + { + "t": "gt", + "v": "38", + "vt": "num" + }, + { + "t": "lte", + "v": "35", + "vt": "num" + } + ], + "checkall": "false", + "repair": false, + "outputs": 2, + "x": 570, + "y": 40, + "wires": [ + [ + "a25d6486.e1ce28" + ], + [ + "5d4f3e71.1bad4" + ] + ] + }, + { + "id": "5d4f3e71.1bad4", + "type": "change", + "z": "1371dec5.76e671", + "name": "Set OFF", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "20", + "tot": "num" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 720, + "y": 60, + "wires": [ + [ + "8485d05.444903" + ] + ] + }, + { + "id": "a25d6486.e1ce28", + "type": "change", + "z": "1371dec5.76e671", + "name": "Set ON", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "100", + "tot": "num" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 720, + "y": 20, + "wires": [ + [ + "8485d05.444903" + ] + ] + }, + { + "id": "569154a.b53182c", + "type": "inject", + "z": "1371dec5.76e671", + "name": "once", + "props": [ + { + "p": "payload" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "", + "topic": "", + "payload": "start", + "payloadType": "str", + "x": 130, + "y": 700, + "wires": [ + [ + "5883e629f5d546ed" + ] + ] + }, + { + "id": "4828d2f4.7c712c", + "type": "function", + "z": "1371dec5.76e671", + "name": "set global", + "func": "global.set(\"acq_instrument_id\",msg.payload);\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 580, + "y": 720, + "wires": [ + [] + ] + }, + { + "id": "e2f39a35.f57298", + "type": "subflow:1c24ad9c.bebec2", + "z": "1371dec5.76e671", + "name": "", + "env": [], + "x": 130, + "y": 640, + "wires": [ + [ + "9b64f397101c2762" + ] + ] + }, + { + "id": "3e64877a.9684b", + "type": "function", + "z": "1371dec5.76e671", + "name": "set global", + "func": "global.set(\"acq_software\", \"PlanktoScope \" + msg.payload);\n", + "outputs": 1, + "timeout": "", + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 820, + "y": 520, + "wires": [ + [] + ] + }, + { + "id": "bdc6718a.dd5d48", + "type": "ui_text", + "z": "1371dec5.76e671", + "group": "ce9e278.781eed8", + "order": 2, + "width": 0, + "height": 0, + "name": "", + "label": "Instrument Type", + "format": "{{msg.payload}}", + "layout": "row-spread", + "className": "", + "style": false, + "font": "", + "fontSize": "", + "color": "#000000", + "x": 600, + "y": 640, + "wires": [] + }, + { + "id": "a400a97e.e333a8", + "type": "ui_text", + "z": "1371dec5.76e671", + "group": "ce9e278.781eed8", + "order": 1, + "width": 0, + "height": 0, + "name": "", + "label": "Instrument Name", + "format": "{{msg.payload}}", + "layout": "row-spread", + "x": 610, + "y": 680, + "wires": [] + }, + { + "id": "8343fa69.49339", + "type": "ui_text", + "z": "1371dec5.76e671", + "group": "ce9e278.781eed8", + "order": 3, + "width": 0, + "height": 0, + "name": "", + "label": "Software Version", + "format": "{{msg.payload}}", + "layout": "row-spread", + "className": "", + "style": false, + "font": "", + "fontSize": "", + "color": "#000000", + "x": 850, + "y": 560, + "wires": [] + }, + { + "id": "f783aefd.c3bfd8", + "type": "ui_text", + "z": "1371dec5.76e671", + "group": "ce9e278.781eed8", + "order": 4, + "width": 0, + "height": 0, + "name": "", + "label": "Camera Name", + "format": "{{msg.payload}}", + "layout": "row-spread", + "x": 600, + "y": 760, + "wires": [] + }, + { + "id": "30067f35.532f2", + "type": "link in", + "z": "1371dec5.76e671", + "name": "Camera Name", + "links": [ + "559a8085.1d6b9" + ], + "x": 155, + "y": 760, + "wires": [ + [ + "f783aefd.c3bfd8" + ] + ] + }, + { + "id": "eaf74a43.fa27d", + "type": "switch", + "z": "1371dec5.76e671", + "name": "if disk > 90%", + "property": "payload", + "propertyType": "msg", + "rules": [ + { + "t": "gte", + "v": "90", + "vt": "num" + } + ], + "checkall": "true", + "repair": false, + "outputs": 1, + "x": 590, + "y": 120, + "wires": [ + [ + "6d09f428.930bcc" + ] + ] + }, + { + "id": "46d5e78b.15f998", + "type": "ui_toast", + "z": "1371dec5.76e671", + "position": "dialog", + "displayTime": "10", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "topic": "", + "name": "", + "x": 1090, + "y": 120, + "wires": [ + [] + ] + }, + { + "id": "24df077a.cb252", + "type": "change", + "z": "1371dec5.76e671", + "name": "full disk msg", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "\"Your drive has reached 90% capacity, you should do a backup to an external drive and a purge.\"", + "tot": "str" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 930, + "y": 120, + "wires": [ + [ + "46d5e78b.15f998" + ] + ] + }, + { + "id": "f344dc9e.3c9278", + "type": "ui_button", + "z": "1371dec5.76e671", + "name": "", + "group": "3ca00bf9.e5cac4", + "order": 1, + "width": 4, + "height": 1, + "passthru": false, + "label": "Home", + "tooltip": "", + "color": "", + "bgcolor": "", + "icon": "home", + "payload": "{\"tab\":\"Home\"}", + "payloadType": "json", + "topic": "", + "x": 430, + "y": 800, + "wires": [ + [ + "5f94b366.e4d3a4" + ] + ] + }, + { + "id": "5f94b366.e4d3a4", + "type": "ui_ui_control", + "z": "1371dec5.76e671", + "name": "", + "events": "change", + "x": 580, + "y": 800, + "wires": [ + [] + ] + }, + { + "id": "f30bf784.90d58", + "type": "ui_dropdown", + "z": "1371dec5.76e671", + "name": "", + "label": "", + "tooltip": "", + "place": "Choose USB device", + "group": "52d1b77.28369c8", + "order": 2, + "width": 0, + "height": 0, + "passthru": false, + "multiple": false, + "options": [ + { + "label": "", + "value": "No Drive Detected", + "type": "str" + } + ], + "payload": "", + "topic": "device_path", + "x": 840, + "y": 840, + "wires": [ + [ + "d1b9fed3.f3ead8" + ] + ] + }, + { + "id": "fe29acc2.c25d18", + "type": "ui_button", + "z": "1371dec5.76e671", + "name": "Detect drive", + "group": "52d1b77.28369c8", + "order": 1, + "width": 0, + "height": 0, + "passthru": false, + "label": "Detect drive", + "tooltip": "", + "color": "", + "bgcolor": "", + "icon": "fa-usb fa-2x", + "payload": "", + "payloadType": "str", + "topic": "", + "x": 150, + "y": 840, + "wires": [ + [ + "4c00cd96.6b2f6c" + ] + ] + }, + { + "id": "4c00cd96.6b2f6c", + "type": "exec", + "z": "1371dec5.76e671", + "command": "lsblk --bytes --json --paths --output-all", + "addpay": false, + "append": "", + "useSpawn": "false", + "timer": "", + "oldrc": false, + "name": "detect drive", + "x": 330, + "y": 840, + "wires": [ + [ + "2dc1e43d.cd3d64" + ], + [], + [] + ] + }, + { + "id": "2dc1e43d.cd3d64", + "type": "json", + "z": "1371dec5.76e671", + "name": "", + "property": "payload", + "action": "", + "pretty": false, + "x": 490, + "y": 840, + "wires": [ + [ + "6b730649.09351" + ] + ] + }, + { + "id": "6b730649.09351", + "type": "change", + "z": "1371dec5.76e671", + "name": "", + "rules": [ + { + "t": "set", + "p": "options", + "pt": "msg", + "to": "[payload.blockdevices.children[mountpoint=null].name]", + "tot": "jsonata" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 660, + "y": 840, + "wires": [ + [ + "f30bf784.90d58" + ] + ] + }, + { + "id": "1ece8d8e.1008e2", + "type": "ui_button", + "z": "1371dec5.76e671", + "name": "Backup to USB", + "group": "52d1b77.28369c8", + "order": 3, + "width": 0, + "height": 0, + "passthru": false, + "label": "Backup to USB", + "tooltip": "", + "color": "", + "bgcolor": "", + "icon": "archive", + "payload": "", + "payloadType": "str", + "topic": "USB Backup", + "x": 160, + "y": 900, + "wires": [ + [ + "6b2fed77.883c0c" + ] + ] + }, + { + "id": "d1b9fed3.f3ead8", + "type": "function", + "z": "1371dec5.76e671", + "name": "set local", + "func": "flow.set(msg.topic,msg.payload);", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 1000, + "y": 840, + "wires": [ + [] + ] + }, + { + "id": "6b2fed77.883c0c", + "type": "function", + "z": "1371dec5.76e671", + "name": "get device_path", + "func": "msg.payload = flow.get(\"device_path\");\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 340, + "y": 900, + "wires": [ + [ + "df4d4d6a.24787" + ] + ] + }, + { + "id": "c74fe76.bcba718", + "type": "exec", + "z": "1371dec5.76e671", + "command": "sudo /home/pi/PlanktoScope/scripts/bash/usb_backup.sh", + "addpay": true, + "append": "", + "useSpawn": "true", + "timer": "", + "oldrc": false, + "name": "usb_backup.sh", + "x": 720, + "y": 920, + "wires": [ + [ + "72f5e8d4.40fcb8" + ], + [], + [ + "a2c36500.6d376" + ] + ] + }, + { + "id": "df4d4d6a.24787", + "type": "switch", + "z": "1371dec5.76e671", + "name": "No Drive", + "property": "payload", + "propertyType": "msg", + "rules": [ + { + "t": "eq", + "v": "No Drive Detected", + "vt": "str" + }, + { + "t": "else" + } + ], + "checkall": "false", + "repair": false, + "outputs": 2, + "x": 520, + "y": 900, + "wires": [ + [ + "9a577caa.1535a" + ], + [ + "c74fe76.bcba718", + "4997446.5176d3c" + ] + ] + }, + { + "id": "9a577caa.1535a", + "type": "ui_toast", + "z": "1371dec5.76e671", + "position": "dialog", + "displayTime": "5", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "topic": "", + "name": "", + "x": 710, + "y": 880, + "wires": [ + [] + ] + }, + { + "id": "72f5e8d4.40fcb8", + "type": "ui_toast", + "z": "1371dec5.76e671", + "position": "top right", + "displayTime": "5", + "highlight": "", + "sendall": true, + "outputs": 0, + "ok": "OK", + "cancel": "", + "raw": false, + "topic": "", + "name": "", + "x": 930, + "y": 900, + "wires": [] + }, + { + "id": "81a48376.27a66", + "type": "ui_toast", + "z": "1371dec5.76e671", + "position": "dialog", + "displayTime": "5", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "topic": "", + "name": "", + "x": 1110, + "y": 980, + "wires": [ + [] + ] + }, + { + "id": "a2c36500.6d376", + "type": "function", + "z": "1371dec5.76e671", + "name": "return code", + "func": "switch (msg.payload.code){\ncase 0:\n msg.payload = \"All files successfully copied, you can remove your usb drive!\";\n break;\ncase 1:\n msg.payload = \"There was an error!\";\n break;\ncase 2:\n msg.payload = \"Error: your device is already mounted\"\n break;\ncase 3:\n msg.payload = \"Error while mounting the device\"\n break;\ncase 4:\n msg.payload = \"Error: some files were corrupted during the copy!\"\n break;\n}\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 910, + "y": 940, + "wires": [ + [ + "81a48376.27a66" + ] + ] + }, + { + "id": "dde0025c.3df9f", + "type": "ui_button", + "z": "1371dec5.76e671", + "name": "Purge local", + "group": "52d1b77.28369c8", + "order": 4, + "width": 0, + "height": 0, + "passthru": false, + "label": "Purge local data", + "tooltip": "", + "color": "", + "bgcolor": "#AD1625", + "icon": "delete_forever", + "payload": "THIS IS GOING TO WIPE ALL THE LOCAL DATA. MAKE SURE YOU DID A BACKUP TO AN USB DRIVE BEFOREHAND.", + "payloadType": "str", + "topic": "BE EXTRA CAREFUL", + "x": 150, + "y": 1020, + "wires": [ + [ + "ba72704a.8a38a" + ] + ] + }, + { + "id": "ba72704a.8a38a", + "type": "ui_toast", + "z": "1371dec5.76e671", + "position": "dialog", + "displayTime": "5", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "GO BACK", + "cancel": "YES I'M SURE, I WANT TO PURGE THE DATA", + "raw": false, + "topic": "Data purge", + "name": "", + "x": 330, + "y": 1020, + "wires": [ + [ + "d80e6307.3aaf8" + ] + ] + }, + { + "id": "d80e6307.3aaf8", + "type": "switch", + "z": "1371dec5.76e671", + "name": "", + "property": "payload", + "propertyType": "msg", + "rules": [ + { + "t": "cont", + "v": "YES I'M SURE", + "vt": "str" + } + ], + "checkall": "true", + "repair": false, + "outputs": 1, + "x": 510, + "y": 1020, + "wires": [ + [ + "4a8cb5d4.52e4bc" + ] + ] + }, + { + "id": "4a8cb5d4.52e4bc", + "type": "exec", + "z": "1371dec5.76e671", + "command": "rm -rf /home/pi/data/img /home/pi/data/objects /home/pi/data/export", + "addpay": false, + "append": "", + "useSpawn": "false", + "timer": "", + "oldrc": false, + "name": "rm data", + "x": 700, + "y": 1020, + "wires": [ + [ + "c5b1e763.d1bba8" + ], + [], + [] + ] + }, + { + "id": "c5b1e763.d1bba8", + "type": "function", + "z": "1371dec5.76e671", + "name": "error message", + "func": "// TODO revoir cette partie\n\nswitch (msg.rc.code){\ncase 0:\n msg.payload = \"/home/pi/data was purged successfully!\";\n break;\ndefault:\n msg.payload = \"There was an error! The error is \" + msg.rc.message;\n break;\n}\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 900, + "y": 1020, + "wires": [ + [ + "81a48376.27a66" + ] + ] + }, + { + "id": "6d09f428.930bcc", + "type": "delay", + "z": "1371dec5.76e671", + "name": "", + "pauseType": "rate", + "timeout": "5", + "timeoutUnits": "seconds", + "rate": "1", + "nbRateUnits": "5", + "rateUnits": "minute", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": true, + "allowrate": false, + "outputs": 1, + "x": 760, + "y": 120, + "wires": [ + [ + "24df077a.cb252" + ] + ] + }, + { + "id": "4997446.5176d3c", + "type": "change", + "z": "1371dec5.76e671", + "name": "Backup starting message", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "\"The backup is starting now, please wait for the complete message before removing the drive\"", + "tot": "str" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 750, + "y": 980, + "wires": [ + [ + "81a48376.27a66" + ] + ] + }, + { + "id": "6c7f0cc5.ea30d4", + "type": "gpsd", + "z": "1371dec5.76e671", + "name": "", + "hostname": "localhost", + "port": "2947", + "tpv": true, + "sky": false, + "info": false, + "device": false, + "gst": false, + "att": false, + "x": 170, + "y": 1360, + "wires": [ + [ + "906072b1.42c7c8", + "cd3b05d6.5a3e2", + "9b29e0e2.475e08", + "96fefa8b.b7d538", + "49a98fe9.9450d8", + "f2a62d0.f5e135" + ] + ] + }, + { + "id": "96bc0179.5c37", + "type": "ui_text", + "z": "1371dec5.76e671", + "group": "cfe2288f.a8862", + "order": 1, + "width": 6, + "height": 1, + "name": "GPS Status Display", + "label": "GPS Status:", + "format": "{{msg.payload}}", + "layout": "row-center", + "x": 660, + "y": 1200, + "wires": [] + }, + { + "id": "8c731f52.2b5f3", + "type": "ui_text", + "z": "1371dec5.76e671", + "group": "cfe2288f.a8862", + "order": 5, + "width": 3, + "height": 1, + "name": "Latitude", + "label": "Latitude", + "format": "{{msg.payload.lat.deg}}°{{msg.payload.lat.min}}'{{msg.payload.lat.sec}}{{msg.payload.lat.dir}}", + "layout": "col-center", + "x": 620, + "y": 1240, + "wires": [] + }, + { + "id": "34e4b5ea.27b4a2", + "type": "ui_text", + "z": "1371dec5.76e671", + "group": "cfe2288f.a8862", + "order": 6, + "width": 3, + "height": 1, + "name": "Longitude", + "label": "Longitude", + "format": "{{msg.payload.lon.deg}}°{{msg.payload.lon.min}}'{{msg.payload.lon.sec}}{{msg.payload.lon.dir}}", + "layout": "col-center", + "x": 620, + "y": 1280, + "wires": [] + }, + { + "id": "906072b1.42c7c8", + "type": "function", + "z": "1371dec5.76e671", + "name": "Convert DD to DMS", + "func": "function ConvertDDToDMS(D, lng){\n // from https://stackoverflow.com/a/5786281/2108279\n return {\n dir : D<0?lng?'W':'S':lng?'E':'N',\n deg : 0|(D<0?D=-D:D),\n min : 0|D%1*60,\n sec :(0|D*60%1*6000)/100\n };\n}\n\nmsg.payload = {\n \"lat\":ConvertDDToDMS(msg.payload.lat, false),\n \"lon\":ConvertDDToDMS(msg.payload.lon, true)\n};\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 420, + "y": 1260, + "wires": [ + [ + "8c731f52.2b5f3", + "34e4b5ea.27b4a2" + ] + ] + }, + { + "id": "4584c817.0be238", + "type": "ui_text", + "z": "1371dec5.76e671", + "group": "cfe2288f.a8862", + "order": 3, + "width": 3, + "height": 1, + "name": "Speed", + "label": "Speed", + "format": "{{msg.payload}} kts", + "layout": "col-center", + "x": 610, + "y": 1320, + "wires": [] + }, + { + "id": "cd3b05d6.5a3e2", + "type": "ui_text", + "z": "1371dec5.76e671", + "group": "cfe2288f.a8862", + "order": 4, + "width": 3, + "height": 1, + "name": "Direction", + "label": "Direction", + "format": "{{msg.payload.track}} °", + "layout": "col-center", + "x": 620, + "y": 1360, + "wires": [] + }, + { + "id": "9b29e0e2.475e08", + "type": "function", + "z": "1371dec5.76e671", + "name": "GPS Mode", + "func": "switch (msg.payload.mode){\n case 1:msg.payload = \"No Fix\"; break\n case 2:msg.payload = \"2D Fix\"; break\n case 3:msg.payload = \"3D Fix\"; break\n default: msg.payload = \"No info\"\n}\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 390, + "y": 1200, + "wires": [ + [ + "96bc0179.5c37" + ] + ] + }, + { + "id": "96fefa8b.b7d538", + "type": "function", + "z": "1371dec5.76e671", + "name": "Speed conversion", + "func": "msg.payload = (0|msg.payload.speed) * 1.9438\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 410, + "y": 1320, + "wires": [ + [ + "4584c817.0be238" + ] + ] + }, + { + "id": "49a98fe9.9450d8", + "type": "ui_text", + "z": "1371dec5.76e671", + "group": "cfe2288f.a8862", + "order": 2, + "width": 6, + "height": 1, + "name": "GPS UTC datetime", + "label": "GPS UTC datetime", + "format": "{{msg.payload.time}}", + "layout": "col-center", + "x": 650, + "y": 1400, + "wires": [] + }, + { + "id": "3c3f334e.d691ac", + "type": "ui_button", + "z": "1371dec5.76e671", + "name": "", + "group": "cfe2288f.a8862", + "order": 6, + "width": 0, + "height": 0, + "passthru": false, + "label": "Force local clock update", + "tooltip": "", + "color": "", + "bgcolor": "", + "icon": "", + "payload": "", + "payloadType": "str", + "topic": "topic", + "x": 670, + "y": 1480, + "wires": [ + [ + "c60030d4.317418" + ] + ] + }, + { + "id": "c60030d4.317418", + "type": "exec", + "z": "1371dec5.76e671", + "command": "sudo hwclock -w", + "addpay": false, + "append": "", + "useSpawn": "false", + "timer": "", + "oldrc": false, + "name": "", + "x": 920, + "y": 1480, + "wires": [ + [], + [], + [] + ] + }, + { + "id": "6d144078.508d9", + "type": "ui_text", + "z": "1371dec5.76e671", + "group": "cfe2288f.a8862", + "order": 2, + "width": 6, + "height": 1, + "name": "Local UTC datetime", + "label": "Local UTC datetime", + "format": "{{msg.payload}}", + "layout": "col-center", + "x": 660, + "y": 1440, + "wires": [] + }, + { + "id": "f2a62d0.f5e135", + "type": "function", + "z": "1371dec5.76e671", + "name": "", + "func": "msg.payload = new Date()\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 380, + "y": 1440, + "wires": [ + [ + "6d144078.508d9" + ] + ] + }, + { + "id": "952db22920d7d5f1", + "type": "rpi-gpio out", + "z": "1371dec5.76e671", + "name": "Fan", + "pin": "13", + "set": false, + "level": "0", + "freq": "25000", + "out": "pwm", + "bcm": true, + "x": 1110, + "y": 40, + "wires": [] + }, + { + "id": "5883e629f5d546ed", + "type": "file in", + "z": "1371dec5.76e671", + "name": "Get machine name", + "filename": "/var/lib/planktoscope/machine-name", + "filenameType": "str", + "format": "utf8", + "chunk": false, + "sendError": false, + "encoding": "none", + "allProps": false, + "x": 350, + "y": 700, + "wires": [ + [ + "a400a97e.e333a8", + "4828d2f4.7c712c" + ] + ] + }, + { + "id": "9b64f397101c2762", + "type": "change", + "z": "1371dec5.76e671", + "name": "Get acq_instrument", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "payload.acq_instrument", + "tot": "msg" + }, + { + "t": "set", + "p": "topic", + "pt": "msg", + "to": "acq_instrument", + "tot": "str" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 350, + "y": 640, + "wires": [ + [ + "bdc6718a.dd5d48" + ] + ] + }, + { + "id": "99725e1437cc390b", + "type": "file in", + "z": "1371dec5.76e671", + "name": "Versioning File", + "filename": "/home/pi/.local/etc/pkscope-distro/installer-versioning.yml", + "filenameType": "str", + "format": "utf8", + "chunk": false, + "sendError": false, + "encoding": "none", + "allProps": false, + "x": 240, + "y": 540, + "wires": [ + [ + "f4e21e28bd903f6d" + ] + ], + "info": "# PlanktoScope Help\nThis Node will read the content of the file named **config.txt** containing all the input placeholders.\n" + }, + { + "id": "6a0fa173874c3ddd", + "type": "inject", + "z": "1371dec5.76e671", + "name": "once", + "props": [ + { + "p": "payload" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "", + "topic": "", + "payload": "start", + "payloadType": "str", + "x": 90, + "y": 540, + "wires": [ + [ + "99725e1437cc390b" + ] + ] + }, + { + "id": "f4e21e28bd903f6d", + "type": "yaml", + "z": "1371dec5.76e671", + "property": "payload", + "name": "", + "x": 390, + "y": 540, + "wires": [ + [ + "d6264e3e29b68c6e", + "aa84b912c996c69e", + "fba22dc2c16b3ec8" + ] + ] + }, + { + "id": "d6264e3e29b68c6e", + "type": "change", + "z": "1371dec5.76e671", + "name": "Get version", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "payload.version", + "tot": "msg" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 590, + "y": 540, + "wires": [ + [ + "3e64877a.9684b", + "8343fa69.49339" + ] + ] + }, + { + "id": "aa84b912c996c69e", + "type": "change", + "z": "1371dec5.76e671", + "name": "Get repo", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "payload.repo", + "tot": "msg" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 580, + "y": 500, + "wires": [ + [ + "fd55e7a43d9bdbbb" + ] + ] + }, + { + "id": "fd55e7a43d9bdbbb", + "type": "function", + "z": "1371dec5.76e671", + "name": "set global", + "func": "global.set(\"process_source\", msg.payload);\n", + "outputs": 1, + "timeout": "", + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 820, + "y": 480, + "wires": [ + [] + ] + }, + { + "id": "fba22dc2c16b3ec8", + "type": "change", + "z": "1371dec5.76e671", + "name": "Get commit", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "payload.commit", + "tot": "msg" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 590, + "y": 580, + "wires": [ + [ + "2ddc75a4ac38a17f" + ] + ] + }, + { + "id": "2ddc75a4ac38a17f", + "type": "function", + "z": "1371dec5.76e671", + "name": "set global", + "func": "global.set(\"process_commit\", msg.payload);\n", + "outputs": 1, + "timeout": "", + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 820, + "y": 600, + "wires": [ + [] + ] + }, + { + "id": "797675a937dc1629", + "type": "ui_template", + "z": "1371dec5.76e671", + "group": "3da7da8f.179606", + "name": "Metrics panel", + "order": 2, + "width": "0", + "height": "0", + "format": "
\n

\n The instrument's system time is different from your web browser's time by {{drift}}.\n As a result, timestamps in your datasets will be incorrect.\n Additionally, system metrics will not be recorded or shown correctly.\n Additionally, you will see incorrectly-aligned graphs in the metrics below.\n

\n

Please change the instrument's system time or your web browser's time to accurate values.

\n

\n \n

\n
\n\n
\n

Loading system metrics, please wait...

\n
\n\n
\n \n
\n\n\n", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 330, + "y": 280, + "wires": [ + [] + ] + }, + { + "id": "aa2e4cd182dbc776", + "type": "function", + "z": "1371dec5.76e671", + "name": "Get system time", + "func": "var date = new Date();\ndate.setSeconds(0, 0);\nmsg.payload = (\n date.toISOString().replace('T', ' ').replace(/:\\d+\\.\\d+Z/,' UTC')\n);\nreturn msg", + "outputs": 1, + "timeout": "", + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 340, + "y": 240, + "wires": [ + [ + "7c9ee522f6dbd3b0" + ] + ] + }, + { + "id": "7c9ee522f6dbd3b0", + "type": "ui_text", + "z": "1371dec5.76e671", + "group": "ce9e278.781eed8", + "order": 5, + "width": 0, + "height": 0, + "name": "", + "label": "System Time", + "format": "{{msg.payload}}", + "layout": "row-spread", + "className": "", + "style": false, + "font": "", + "fontSize": "", + "color": "#000000", + "x": 590, + "y": 240, + "wires": [] + }, + { + "id": "6dc9862f2eebe935", + "type": "http in", + "z": "1371dec5.76e671", + "name": "POST /api/system-time", + "url": "/api/system-time", + "method": "post", + "upload": false, + "swaggerDoc": "", + "x": 120, + "y": 360, + "wires": [ + [ + "a7994a561866dc94", + "dea222e9a6553cac" + ] + ] + }, + { + "id": "1c4113d4c933fd4b", + "type": "ui_toast", + "z": "1371dec5.76e671", + "position": "top right", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 0, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "Setting system time", + "name": "", + "x": 610, + "y": 340, + "wires": [] + }, + { + "id": "a7994a561866dc94", + "type": "function", + "z": "1371dec5.76e671", + "name": "Get system time", + "func": "var date = new Date(msg.payload.timestamp);\nmsg.payload = (\n date.toISOString().replace('T', ' ').replace(/:\\d+\\.\\d+Z/,' UTC')\n);\nreturn msg", + "outputs": 1, + "timeout": "", + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 340, + "y": 340, + "wires": [ + [ + "1c4113d4c933fd4b" + ] + ] + }, + { + "id": "814ce40bfc413777", + "type": "exec", + "z": "1371dec5.76e671", + "command": "sudo date -s", + "addpay": "payload", + "append": "", + "useSpawn": "", + "timer": "", + "winHide": false, + "name": "Set system time", + "x": 600, + "y": 380, + "wires": [ + [], + [], + [] + ] + }, + { + "id": "dea222e9a6553cac", + "type": "function", + "z": "1371dec5.76e671", + "name": "Prepare timestamp", + "func": "msg.payload = ('@' + msg.payload.timestamp).slice(0, -3);\nreturn msg;", + "outputs": 1, + "timeout": "", + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 350, + "y": 380, + "wires": [ + [ + "814ce40bfc413777" + ] + ] + }, + { + "id": "f6f570b10c675854", + "type": "ui_template", + "z": "1371dec5.76e671", + "group": "ce9e278.781eed8", + "name": "Browser time", + "order": 6, + "width": "6", + "height": "1", + "format": "
\n

Browser Time

\n

{{time}}

\n
\n\n", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 330, + "y": 200, + "wires": [ + [] + ] + }, + { + "id": "b9bf06d6.26c518", + "type": "exec", + "z": "f21ba04.c26266", + "command": "sudo iwlist wlan0 scan | grep ESSID | sed 's/ESSID://g;s/\"//g;s/^ *//;s/ *$//'", + "addpay": false, + "append": "", + "useSpawn": "false", + "timer": "", + "oldrc": false, + "name": "scan", + "x": 450, + "y": 80, + "wires": [ + [ + "9642cb31.663b4" + ], + [], + [] + ] + }, + { + "id": "9642cb31.663b4", + "type": "function", + "z": "f21ba04.c26266", + "name": "parseOptions", + "func": "var ssids = msg.payload.split('\\n').filter(s => !!s)\n\nssids = [...new Set(ssids)];\n\nmsg.options = ssids\nmsg.payload = null\n\nreturn msg;", + "outputs": 1, + "noerr": 0, + "x": 640, + "y": 80, + "wires": [ + [ + "dbc0d44.5361b28" + ] + ] + }, + { + "id": "dbc0d44.5361b28", + "type": "ui_dropdown", + "z": "f21ba04.c26266", + "name": "", + "label": "Wifi", + "tooltip": "", + "place": "Select a WIFI", + "group": "9e409235.73cd7", + "order": 1, + "width": 0, + "height": 0, + "passthru": false, + "multiple": false, + "options": [], + "payload": "", + "topic": "", + "x": 830, + "y": 80, + "wires": [ + [ + "cdfa9013.b91278" + ] + ] + }, + { + "id": "2bf338e3.966468", + "type": "ui_button", + "z": "f21ba04.c26266", + "name": "", + "group": "9e409235.73cd7", + "order": 2, + "width": 0, + "height": 0, + "passthru": false, + "label": "Scan", + "tooltip": "", + "color": "", + "bgcolor": "", + "icon": "fa-wifi fa-2x", + "payload": "true", + "payloadType": "bool", + "topic": "", + "x": 270, + "y": 40, + "wires": [ + [ + "b9bf06d6.26c518" + ] + ] + }, + { + "id": "4c0400c.69a1e8", + "type": "exec", + "z": "f21ba04.c26266", + "command": "ip -j addr show", + "addpay": false, + "append": "", + "useSpawn": "false", + "timer": "", + "oldrc": false, + "name": "getInfo", + "x": 450, + "y": 180, + "wires": [ + [ + "88e05f37a8745216" + ], + [], + [] + ] + }, + { + "id": "bcb20e39.00cea8", + "type": "function", + "z": "f21ba04.c26266", + "name": "parse IP Info", + "func": "var ip = \"\";\nvar broadcast = \"\";\nvar iface = \"\";\nvar iface_up = false;\n\nif (msg.rc.code === 0){\n payload = msg.payload\n for (let info in payload) {\n if (payload[info].operstate === \"UP\") {\n \tif (iface_up){\n \t// We have two concurrent interfaces up\n // We need to deactivate one\n ip = \"Remove Ethernet cable or disconnect wifi\"\n broadcast = \"Remove Ethernet cable or disconnect wifi\"\n iface = \"Remove Ethernet cable or disconnect wifi\"\n break\n }\n if (payload[info].ifname === \"eth0\") {\n iface = \"Ethernet\"\n } else if (payload[info].ifname === \"wifi0\" || payload[info].ifname === \"wlan0\") {\n iface = \"Wifi\"\n }\n ip = payload[info].addr_info[0].local;\n broadcast = payload[info].addr_info[0].broadcast;\n iface_up = true;\n }\n }\n}\n\nif (iface_up) {\n return([{\n topic: 'interface',\n payload: iface\n }, {\n topic: 'ip',\n payload: ip\n }, {\n topic: 'broadcast',\n payload: broadcast\n }])\n}\n", + "outputs": 3, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 730, + "y": 180, + "wires": [ + [ + "67d052ba.99ff24" + ], + [ + "d71c8185.800fd" + ], + [ + "dc305a26.b33fc" + ] + ], + "outputLabels": [ + "interface", + "ip", + "broadcast" + ] + }, + { + "id": "d71c8185.800fd", + "type": "ui_text", + "z": "f21ba04.c26266", + "group": "919923a3.d10868", + "order": 2, + "width": 0, + "height": 0, + "name": "", + "label": "IP", + "format": "{{msg.payload || '---'}}", + "layout": "row-spread", + "x": 930, + "y": 180, + "wires": [] + }, + { + "id": "67d052ba.99ff24", + "type": "ui_text", + "z": "f21ba04.c26266", + "group": "919923a3.d10868", + "order": 1, + "width": 0, + "height": 0, + "name": "", + "label": "Interface", + "format": "{{msg.payload || '---'}}", + "layout": "row-spread", + "x": 940, + "y": 140, + "wires": [] + }, + { + "id": "dc305a26.b33fc", + "type": "ui_text", + "z": "f21ba04.c26266", + "group": "919923a3.d10868", + "order": 3, + "width": 0, + "height": 0, + "name": "", + "label": "Broadcast", + "format": "{{msg.payload || '---'}}", + "layout": "row-spread", + "x": 950, + "y": 219, + "wires": [] + }, + { + "id": "94b2e8fc.aa20e", + "type": "ui_form", + "z": "f21ba04.c26266", + "name": "", + "label": "Update", + "group": "9e409235.73cd7", + "order": 3, + "width": 0, + "height": 0, + "options": [ + { + "label": "SSID", + "value": "ssid", + "type": "text", + "required": true, + "rows": null + }, + { + "label": "Password", + "value": "password", + "type": "text", + "required": true, + "rows": null + } + ], + "formValue": { + "ssid": "", + "password": "" + }, + "payload": "", + "submit": "Add the network", + "cancel": "Reset fields", + "topic": "", + "x": 1160, + "y": 80, + "wires": [ + [ + "d59021e3.1b63e8" + ] + ] + }, + { + "id": "cdfa9013.b91278", + "type": "function", + "z": "f21ba04.c26266", + "name": "insert ssid", + "func": "\nmsg.payload = {ssid: msg.payload}\n\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 990, + "y": 80, + "wires": [ + [ + "94b2e8fc.aa20e" + ] + ] + }, + { + "id": "448b4c37.be50bc", + "type": "exec", + "z": "f21ba04.c26266", + "command": "iw dev wlan0 info", + "addpay": false, + "append": "", + "useSpawn": "false", + "timer": "", + "oldrc": false, + "name": "getCurrentSSID", + "x": 480, + "y": 260, + "wires": [ + [ + "151819d4.0dbe56" + ], + [], + [] + ] + }, + { + "id": "c8a5ae48.ef1308", + "type": "ui_text", + "z": "f21ba04.c26266", + "group": "919923a3.d10868", + "order": 4, + "width": 0, + "height": 0, + "name": "", + "label": "SSID", + "format": "{{msg.payload || '---'}}", + "layout": "row-spread", + "x": 930, + "y": 259, + "wires": [] + }, + { + "id": "151819d4.0dbe56", + "type": "function", + "z": "f21ba04.c26266", + "name": "parse SSID", + "func": "var ssid = \"\"\n\nif (msg.rc.code === 0){\n ssid = msg.payload.match(/\\sssid (.+)/)[1];\n return({topic: 'ssid', payload: ssid})\n}\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 730, + "y": 260, + "wires": [ + [ + "c8a5ae48.ef1308" + ] + ] + }, + { + "id": "ff059f3f.9c0f28", + "type": "ui_ui_control", + "z": "f21ba04.c26266", + "name": "onTab", + "events": "all", + "x": 130, + "y": 80, + "wires": [ + [ + "f103cd20eb4362a4" + ] + ] + }, + { + "id": "167d7bd0.679ce4", + "type": "function", + "z": "f21ba04.c26266", + "name": "update contry code", + "func": "var template = `sudo sed -i \\\"s/^country.*/country=\"${msg.payload}\"/\\\" /home/pi/wpa_supplicant.conf`\n// sudo tee /etc/wpa_supplicant/wpa_supplicant.conf < /dev/null`\n \nmsg.payload = command\n\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 1330, + "y": 80, + "wires": [ + [ + "64a1f2f2.3de8b4" + ] + ] + }, + { + "id": "64a1f2f2.3de8b4", + "type": "exec", + "z": "f21ba04.c26266", + "command": "", + "addpay": true, + "append": "", + "useSpawn": "false", + "timer": "", + "oldrc": false, + "name": "Save Network", + "x": 1520, + "y": 80, + "wires": [ + [ + "6868b4c4.65987c" + ], + [], + [] + ] + }, + { + "id": "6868b4c4.65987c", + "type": "exec", + "z": "f21ba04.c26266", + "command": "sudo /usr/bin/autohotspotN >/dev/null", + "addpay": false, + "append": "", + "useSpawn": "true", + "timer": "", + "oldrc": false, + "name": "reconfigure", + "x": 1710, + "y": 80, + "wires": [ + [ + "59e24c40.e1a4dc" + ], + [], + [] + ] + }, + { + "id": "59e24c40.e1a4dc", + "type": "function", + "z": "f21ba04.c26266", + "name": "showMessage", + "func": "msg.payload = \"Wifi configuration updated successfully, please connect to the network you just used.\"\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "x": 1440, + "y": 180, + "wires": [ + [ + "4ecb6be2.ad39f4" + ] + ] + }, + { + "id": "4ecb6be2.ad39f4", + "type": "ui_toast", + "z": "f21ba04.c26266", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "topic": "", + "name": "", + "x": 1650, + "y": 180, + "wires": [ + [] + ] + }, + { + "id": "991d1df9.3ffb3", + "type": "function", + "z": "f21ba04.c26266", + "name": "reset wpa_supplicant.conf", + "func": "country_code = flow.get(\"country_code\")\n\nvar template = `sudo tee /etc/wpa_supplicant/wpa_supplicant.conf <Stepper controller type", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 550, + "y": 100, + "wires": [ + [] + ] + }, + { + "id": "7534dfd9.8cf3e8", + "type": "ui_template", + "z": "1eaf21c8.f7a21e", + "group": "6be36295.0ab324", + "name": "Information", + "order": 1, + "width": "8", + "height": "3", + "format": "
\n

\n Changing one of these values will cause the Python hardware controller to restart, to reload the new hardware configuration.\n

\n

\n Warning: selecting a hardware version from the dropdown menu below will also overwrite all of your hardware settings, including your camera white balance settings.\n

\n

\n If you are not sure, you probably should not be touching anything here!\n

\n
\n", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 610, + "y": 60, + "wires": [ + [] + ] + }, + { + "id": "a7e5c7f4.644678", + "type": "ui_dropdown", + "z": "1eaf21c8.f7a21e", + "name": "", + "label": "Hardware version", + "tooltip": "", + "place": "Select option", + "group": "6be36295.0ab324", + "order": 2, + "width": 0, + "height": 0, + "passthru": false, + "multiple": false, + "options": [ + { + "label": "", + "value": "PlanktoScope v2.1", + "type": "str" + }, + { + "label": "", + "value": "PlanktoScope v2.3", + "type": "str" + }, + { + "label": "", + "value": "PlanktoScope v2.5", + "type": "str" + }, + { + "label": "", + "value": "PlanktoScope v2.6", + "type": "str" + } + ], + "payload": "", + "topic": "acq_instrument", + "topicType": "str", + "className": "", + "x": 590, + "y": 160, + "wires": [ + [ + "3e2c5c1c.4c57b4", + "68703ef63da2f081", + "d276ce894f483bcf" + ] + ] + }, + { + "id": "1cfadc66.3cde8c", + "type": "subflow:1c24ad9c.bebec2", + "z": "1eaf21c8.f7a21e", + "name": "", + "env": [], + "x": 990, + "y": 160, + "wires": [ + [] + ] + }, + { + "id": "3e2c5c1c.4c57b4", + "type": "function", + "z": "1eaf21c8.f7a21e", + "name": "Save global", + "func": "global.set(msg.topic,msg.payload);\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 830, + "y": 160, + "wires": [ + [ + "1cfadc66.3cde8c" + ] + ] + }, + { + "id": "427c312.fc5e65", + "type": "subflow:1c24ad9c.bebec2", + "z": "1eaf21c8.f7a21e", + "name": "", + "env": [], + "x": 150, + "y": 160, + "wires": [ + [ + "c00c6732b9f36adb" + ] + ] + }, + { + "id": "c67c305004f87e39", + "type": "change", + "z": "1eaf21c8.f7a21e", + "name": "Get process_pixel_fixed", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "payload.process_pixel_fixed", + "tot": "msg" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 670, + "y": 480, + "wires": [ + [ + "244ca5dd62df2bcd" + ] + ] + }, + { + "id": "244ca5dd62df2bcd", + "type": "ui_text_input", + "z": "1eaf21c8.f7a21e", + "name": "process_pixel_fixed", + "label": "Pixel size calibration: um per pixel", + "tooltip": "Object size in µm / pixel. 0 will remove this calibration.", + "group": "6be36295.0ab324", + "order": 8, + "width": 0, + "height": 0, + "passthru": true, + "mode": "number", + "delay": "1000", + "topic": "process_pixel_fixed", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 940, + "y": 480, + "wires": [ + [ + "8e3b3d3c.955148", + "f9b47f4b1da15778" + ] + ] + }, + { + "id": "f9b47f4b1da15778", + "type": "function", + "z": "1eaf21c8.f7a21e", + "name": "Set or remove if null", + "func": "if (msg.payload == 0){\n global.set(msg.topic,undefined)\n}\nelse {\n global.set(msg.topic,msg.payload);\n}\n\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 1220, + "y": 480, + "wires": [ + [ + "5d5ad36d2c50dcc2" + ] + ] + }, + { + "id": "5d5ad36d2c50dcc2", + "type": "link out", + "z": "1eaf21c8.f7a21e", + "name": "Process_pixel calibration", + "links": [ + "cfc783d7.d6ceb" + ], + "x": 1495, + "y": 500, + "wires": [] + }, + { + "id": "6146ba22df928516", + "type": "ui_dropdown", + "z": "1eaf21c8.f7a21e", + "name": "acq_fnumber_objective", + "label": "M12 Lens", + "tooltip": "", + "place": "Select option", + "group": "6be36295.0ab324", + "order": 7, + "width": 0, + "height": 0, + "passthru": true, + "multiple": false, + "options": [ + { + "label": "f 25mm 1/2\" 5MP IR", + "value": 25, + "type": "num" + }, + { + "label": "f 16mm 1/2.5\" 5MP IR", + "value": 16, + "type": "num" + }, + { + "label": "f 12mm 1/2.5\" 5MP IR", + "value": 12, + "type": "num" + }, + { + "label": "f 8mm 1/2.5\" 5MP IR", + "value": 8, + "type": "num" + }, + { + "label": "f 6mm 1/2.5\" 5MP IR", + "value": 6, + "type": "num" + } + ], + "payload": "", + "topic": "acq_fnumber_objective", + "topicType": "str", + "x": 930, + "y": 520, + "wires": [ + [ + "a6983d3232b570a7", + "8e3b3d3c.955148" + ] + ] + }, + { + "id": "a6983d3232b570a7", + "type": "change", + "z": "1eaf21c8.f7a21e", + "name": "", + "rules": [ + { + "t": "set", + "p": "acq_fnumber_objective", + "pt": "global", + "to": "payload", + "tot": "msg" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 1260, + "y": 520, + "wires": [ + [ + "5d5ad36d2c50dcc2" + ] + ] + }, + { + "id": "11955bbeefc29ab4", + "type": "change", + "z": "1eaf21c8.f7a21e", + "name": "Get acq_fnumber_objective", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "payload.acq_fnumber_objective", + "tot": "msg" + }, + { + "t": "set", + "p": "topic", + "pt": "msg", + "to": "acq_fnumber_objective", + "tot": "str" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 680, + "y": 520, + "wires": [ + [ + "6146ba22df928516" + ] + ] + }, + { + "id": "d276ce894f483bcf", + "type": "ui_toast", + "z": "1eaf21c8.f7a21e", + "position": "top right", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 0, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "Resetting hardware configuration to version-specific default", + "name": "", + "x": 850, + "y": 120, + "wires": [] + }, + { + "id": "68703ef63da2f081", + "type": "change", + "z": "1eaf21c8.f7a21e", + "name": "Choose default hardware config", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "$join([\"/home/pi/device-backend/default-configs/\", $substringAfter(msg.payload, \"PlanktoScope \"), \".hardware.json\"])", + "tot": "jsonata" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 230, + "y": 240, + "wires": [ + [ + "e3ba6ac89221b17b" + ] + ] + }, + { + "id": "e3ba6ac89221b17b", + "type": "exec", + "z": "1eaf21c8.f7a21e", + "command": "cp", + "addpay": "payload", + "append": "/home/pi/PlanktoScope/hardware.json", + "useSpawn": "false", + "timer": "", + "winHide": false, + "oldrc": false, + "name": "Copy default hardware config", + "x": 520, + "y": 240, + "wires": [ + [ + "97e582080deae888" + ], + [], + [] + ] + }, + { + "id": "97e582080deae888", + "type": "delay", + "z": "1eaf21c8.f7a21e", + "name": "", + "pauseType": "delay", + "timeout": "500", + "timeoutUnits": "milliseconds", + "rate": "1", + "nbRateUnits": "1", + "rateUnits": "second", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": false, + "allowrate": false, + "outputs": 1, + "x": 750, + "y": 240, + "wires": [ + [ + "3973b999ee7b3b1d", + "3bcaf757cbc77fbe" + ] + ] + }, + { + "id": "3973b999ee7b3b1d", + "type": "link out", + "z": "1eaf21c8.f7a21e", + "name": "Reload hardware config", + "mode": "link", + "links": [ + "5984b086eddc9311" + ], + "x": 915, + "y": 240, + "wires": [] + }, + { + "id": "3bcaf757cbc77fbe", + "type": "subflow:b7861ce703215a01", + "z": "1eaf21c8.f7a21e", + "name": "", + "x": 380, + "y": 440, + "wires": [ + [ + "e10f5e55.00b828", + "54ba7f16.709ad8", + "c534fd26.13741", + "c67c305004f87e39", + "11955bbeefc29ab4" + ] + ] + }, + { + "id": "862235d10aae5b83", + "type": "inject", + "z": "1eaf21c8.f7a21e", + "name": "Once", + "props": [], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": 0.1, + "topic": "", + "x": 150, + "y": 440, + "wires": [ + [ + "3bcaf757cbc77fbe" + ] + ] + }, + { + "id": "c00c6732b9f36adb", + "type": "change", + "z": "1eaf21c8.f7a21e", + "name": "Get acq_instrument", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "payload.acq_instrument", + "tot": "msg" + }, + { + "t": "set", + "p": "topic", + "pt": "msg", + "to": "acq_instrument", + "tot": "str" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 350, + "y": 160, + "wires": [ + [ + "a7e5c7f4.644678" + ] + ] + } +] \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..5a9b724 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1113 @@ +{ + "name": "planktoscope-node-red-dashboard", + "version": "2023.9.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "planktoscope-node-red-dashboard", + "version": "2023.9.0", + "dependencies": { + "node-red-contrib-dir2files": "^0.3.0", + "node-red-contrib-python3-function": "^0.0.4", + "node-red-contrib-ui-multistate-switch": "^1.2.2", + "node-red-dashboard": "^3.1.2", + "node-red-node-ui-list": "^0.3.6" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" + }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" + }, + "node_modules/@types/cors": { + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz", + "integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "20.5.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.6.tgz", + "integrity": "sha512-Gi5wRGPbbyOTX+4Y2iULQ27oUPrefaB0PxGQJnfyWN3kvEDGM3mIB5M/gQLmitZf7A9FmLeaqxD3L1CXpm3VKQ==" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/engine.io": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.2.tgz", + "integrity": "sha512-IXsMcGpw/xRfjra46sVZVHiSWo/nJ/3g1337q9KNXtS6YRzbW5yIzTCb9DjhrBe7r3GZQR0I4+nq+4ODk5g/cA==", + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz", + "integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/engine.io/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/gridstack": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/gridstack/-/gridstack-0.6.4.tgz", + "integrity": "sha512-4ToCnneNg5Uw+ms3xHtPVvsNXdvwQhngdlyNgGkARwvooQu+gLL6xkwPqLU59TsZP/LVvofb2QhEuXyh/ocL8w==", + "dependencies": { + "jquery": "^1.8 || 2 || 3" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/jquery": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.0.tgz", + "integrity": "sha512-umpJ0/k8X0MvD1ds0P9SfowREz2LenHsQaxSohMZ5OMNEU2r0tf8pdeEFTHMFxWVxKNyU9rTtK3CWzUCTKJUeQ==" + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "bin": { + "mustache": "bin/mustache" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-red-contrib-dir2files": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/node-red-contrib-dir2files/-/node-red-contrib-dir2files-0.3.0.tgz", + "integrity": "sha512-1aO+tcHmPvkAMiQ2yTbxzWO4UME2dX1YGNnjZF7guIbRpVigKRk+aO/kC78irJ1hFrtpcc9I3dh920zV4Bivew==", + "dependencies": { + "fs-extra": "^7.0.1", + "path": "^0.12.7" + } + }, + "node_modules/node-red-contrib-python3-function": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/node-red-contrib-python3-function/-/node-red-contrib-python3-function-0.0.4.tgz", + "integrity": "sha512-m7JOWdUQCrX2g7IoCPUlyu1jQt31egYCbGbFenw+nB/28VMtjs9tTYrPxpraPfxU89oQ7XeiiQzq4DWKD3MAKw==" + }, + "node_modules/node-red-contrib-ui-multistate-switch": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/node-red-contrib-ui-multistate-switch/-/node-red-contrib-ui-multistate-switch-1.2.3.tgz", + "integrity": "sha512-Bh4FiSllZSiVIWv8praWrkIM98noX47oUFQ7jVsFM9VIWA33Rda6QMh+HslT8dpjniSBrVWXBDWkrIVDwWQW8Q==", + "dependencies": { + "mustache": "^4.2.0" + } + }, + "node_modules/node-red-dashboard": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/node-red-dashboard/-/node-red-dashboard-3.5.0.tgz", + "integrity": "sha512-pTGz/v7MHEUVMXokqV5wrixTyW1SGI5v5ALJkA+p7vTBh4Ho1zjAb7uc63iJkgrSHRuu0S+E1oSb9SbqKeVTCA==", + "dependencies": { + "compression": "^1.7.4", + "gridstack": "^0.6.4", + "serve-static": "^1.15.0", + "socket.io": "^4.5.4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/node-red-node-ui-list": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/node-red-node-ui-list/-/node-red-node-ui-list-0.3.6.tgz", + "integrity": "sha512-JoCJEFmLLuRRBeCP0PsqNL8YNNGYFoINnXG/ZzGLe0rovXpEshxLekpy1qR7aJQE5hRa+4KAzGBfoBQQRerUAw==", + "peerDependencies": { + "node-red-dashboard": ">2.15.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path": { + "version": "0.12.7", + "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", + "integrity": "sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==", + "dependencies": { + "process": "^0.11.1", + "util": "^0.10.3" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/socket.io": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.2.tgz", + "integrity": "sha512-bvKVS29/I5fl2FGLNHuXlQaUH/BlzX1IN6S+NKLNZpBsPZIDH+90eQmCs2Railn4YUiww4SzUedJ6+uzwFnKLw==", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.5.2", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz", + "integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==", + "dependencies": { + "ws": "~8.11.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io-parser/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/socket.io/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "dependencies": { + "inherits": "2.0.3" + } + }, + "node_modules/util/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + }, + "dependencies": { + "@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" + }, + "@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" + }, + "@types/cors": { + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz", + "integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==", + "requires": { + "@types/node": "*" + } + }, + "@types/node": { + "version": "20.5.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.6.tgz", + "integrity": "sha512-Gi5wRGPbbyOTX+4Y2iULQ27oUPrefaB0PxGQJnfyWN3kvEDGM3mIB5M/gQLmitZf7A9FmLeaqxD3L1CXpm3VKQ==" + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==" + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + } + }, + "cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" + }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, + "engine.io": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.2.tgz", + "integrity": "sha512-IXsMcGpw/xRfjra46sVZVHiSWo/nJ/3g1337q9KNXtS6YRzbW5yIzTCb9DjhrBe7r3GZQR0I4+nq+4ODk5g/cA==", + "requires": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "engine.io-parser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz", + "integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" + }, + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "gridstack": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/gridstack/-/gridstack-0.6.4.tgz", + "integrity": "sha512-4ToCnneNg5Uw+ms3xHtPVvsNXdvwQhngdlyNgGkARwvooQu+gLL6xkwPqLU59TsZP/LVvofb2QhEuXyh/ocL8w==", + "requires": { + "jquery": "^1.8 || 2 || 3" + } + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "jquery": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.0.tgz", + "integrity": "sha512-umpJ0/k8X0MvD1ds0P9SfowREz2LenHsQaxSohMZ5OMNEU2r0tf8pdeEFTHMFxWVxKNyU9rTtK3CWzUCTKJUeQ==" + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==" + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + }, + "node-red-contrib-dir2files": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/node-red-contrib-dir2files/-/node-red-contrib-dir2files-0.3.0.tgz", + "integrity": "sha512-1aO+tcHmPvkAMiQ2yTbxzWO4UME2dX1YGNnjZF7guIbRpVigKRk+aO/kC78irJ1hFrtpcc9I3dh920zV4Bivew==", + "requires": { + "fs-extra": "^7.0.1", + "path": "^0.12.7" + } + }, + "node-red-contrib-python3-function": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/node-red-contrib-python3-function/-/node-red-contrib-python3-function-0.0.4.tgz", + "integrity": "sha512-m7JOWdUQCrX2g7IoCPUlyu1jQt31egYCbGbFenw+nB/28VMtjs9tTYrPxpraPfxU89oQ7XeiiQzq4DWKD3MAKw==" + }, + "node-red-contrib-ui-multistate-switch": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/node-red-contrib-ui-multistate-switch/-/node-red-contrib-ui-multistate-switch-1.2.3.tgz", + "integrity": "sha512-Bh4FiSllZSiVIWv8praWrkIM98noX47oUFQ7jVsFM9VIWA33Rda6QMh+HslT8dpjniSBrVWXBDWkrIVDwWQW8Q==", + "requires": { + "mustache": "^4.2.0" + } + }, + "node-red-dashboard": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/node-red-dashboard/-/node-red-dashboard-3.5.0.tgz", + "integrity": "sha512-pTGz/v7MHEUVMXokqV5wrixTyW1SGI5v5ALJkA+p7vTBh4Ho1zjAb7uc63iJkgrSHRuu0S+E1oSb9SbqKeVTCA==", + "requires": { + "compression": "^1.7.4", + "gridstack": "^0.6.4", + "serve-static": "^1.15.0", + "socket.io": "^4.5.4" + } + }, + "node-red-node-ui-list": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/node-red-node-ui-list/-/node-red-node-ui-list-0.3.6.tgz", + "integrity": "sha512-JoCJEFmLLuRRBeCP0PsqNL8YNNGYFoINnXG/ZzGLe0rovXpEshxLekpy1qR7aJQE5hRa+4KAzGBfoBQQRerUAw==", + "requires": {} + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path": { + "version": "0.12.7", + "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", + "integrity": "sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==", + "requires": { + "process": "^0.11.1", + "util": "^0.10.3" + } + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==" + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + } + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "socket.io": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.2.tgz", + "integrity": "sha512-bvKVS29/I5fl2FGLNHuXlQaUH/BlzX1IN6S+NKLNZpBsPZIDH+90eQmCs2Railn4YUiww4SzUedJ6+uzwFnKLw==", + "requires": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.5.2", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "socket.io-adapter": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz", + "integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==", + "requires": { + "ws": "~8.11.0" + } + }, + "socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + }, + "util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "requires": { + "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + } + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" + }, + "ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "requires": {} + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..0d5602a --- /dev/null +++ b/package.json @@ -0,0 +1,21 @@ +{ + "name": "planktoscope-node-red-dashboard", + "description": "PlanktoScope graphical user interface", + "version": "2023.9.0", + "dependencies": { + "node-red-contrib-dir2files": "^0.3.0", + "node-red-contrib-python3-function": "^0.0.4", + "node-red-contrib-ui-multistate-switch": "^1.2.2", + "node-red-dashboard": "^3.1.2", + "node-red-node-ui-list": "^0.3.6" + }, + "node-red": { + "settings": { + "flowFile": "flows.json", + "credentialsFile": "credentials.json" + } + }, + "scripts": { + "start": "node $NODE_OPTIONS node_modules/node-red/red.js $FLOWS" + } +}