From ea602ede24e49f0d456df0cb97ead3dea531803d Mon Sep 17 00:00:00 2001 From: tpollina Date: Tue, 14 Jul 2020 18:27:49 +0200 Subject: [PATCH] Update flows.json --- flows/flows.json | 3139 +++++++++++++++++++--------------------------- 1 file changed, 1286 insertions(+), 1853 deletions(-) diff --git a/flows/flows.json b/flows/flows.json index 84e7f3f..4106b23 100644 --- a/flows/flows.json +++ b/flows/flows.json @@ -1,13 +1,6 @@ [ { - "id": "ff9251a5.9c5e18", - "type": "tab", - "label": "Main", - "disabled": false, - "info": "" - }, - { - "id": "bba19d97.b32b1", + "id": "97600dff.93378", "type": "subflow", "name": "Acquisition actuation", "info": "", @@ -18,1139 +11,9 @@ "color": "#A6BBCF" }, { - "id": "c1d3ff7c.4384f", - "type": "subflow", - "name": "MQQT Cmds", - "info": "", - "category": "", - "in": [ - { - "x": 40, - "y": 40, - "wires": [ - { - "id": "5079cccb.298d14" - }, - { - "id": "197215b2.165f22" - } - ] - } - ], - "out": [], - "env": [], - "color": "#DDAA99" - }, - { - "id": "c10e968b.87e488", - "type": "subflow", - "name": "Datetime update", - "info": "", - "category": "", - "in": [ - { - "x": 140, - "y": 80, - "wires": [ - { - "id": "93b9f3cd.759688" - } - ] - } - ], - "out": [], - "env": [], - "color": "#DDAA99", - "icon": "font-awesome/fa-clock-o" - }, - { - "id": "863e8384.56889", - "type": "subflow", - "name": "Acquisition inputs", - "info": "", - "category": "", - "in": [ - { - "x": 40, - "y": 40, - "wires": [ - { - "id": "3eaf4c98.d94b54" - }, - { - "id": "e50aa637.59ac68" - }, - { - "id": "8eeb9e9e.a50d7" - }, - { - "id": "e4e16eb9.5296c" - } - ] - } - ], - "out": [ - { - "x": 740, - "y": 40, - "wires": [ - { - "id": "c4527705.33a84", - "port": 0 - }, - { - "id": "f648e44.94e3998", - "port": 0 - }, - { - "id": "582e21b2.ad67a8", - "port": 0 - }, - { - "id": "f9705bc.3d322a8", - "port": 0 - } - ] - } - ], - "env": [], - "color": "#A6BBCF", - "icon": "node-red-contrib-camerapi/photo.png" - }, - { - "id": "5a287804.a10e2", - "type": "subflow", - "name": "Process metadata", - "info": "", - "category": "", - "in": [ - { - "x": 40, - "y": 80, - "wires": [ - { - "id": "dfb4b682.601e1" - } - ] - } - ], - "out": [ - { - "x": 700, - "y": 80, - "wires": [ - { - "id": "11b31baf.95996c", - "port": 0 - } - ] - } - ], - "env": [], - "color": "#DDAA99" - }, - { - "id": "a8ad6dec.1a393", - "type": "subflow", - "name": "MQTT Receive & Plot", - "info": "", - "category": "", - "in": [], - "out": [], - "env": [], - "color": "#F3B567", - "icon": "node-red/bridge.svg" - }, - { - "id": "9882c53a.0ccc8", - "type": "subflow", - "name": "Temperature regulation", - "info": "", - "category": "", - "in": [], - "out": [], - "env": [], - "color": "#FFCC66", - "icon": "font-awesome/fa-bolt" - }, - { - "id": "fbe9590f.bd63b8", - "type": "subflow", - "name": "System Commands", - "info": "", - "category": "", - "in": [], - "out": [], - "env": [], - "color": "#FFCC66", - "icon": "node-red-dashboard/ui_button.png" - }, - { - "id": "b45c6fb6.f6dfa8", - "type": "subflow", - "name": "Object metadata", - "info": "", - "category": "", - "in": [ - { - "x": 40, - "y": 40, - "wires": [ - { - "id": "8a61177.8eaa1e8" - }, - { - "id": "3893c81e.a9b9e" - }, - { - "id": "bd643763.2a7768" - } - ] - } - ], - "out": [ - { - "x": 1060, - "y": 159, - "wires": [ - { - "id": "cf0b247b.e3e7c", - "port": 0 - }, - { - "id": "1675637a.1d762d", - "port": 0 - } - ] - }, - { - "x": 1060, - "y": 59, - "wires": [ - { - "id": "d485fec3.802e", - "port": 0 - }, - { - "id": "5196107b.a5eae8", - "port": 0 - } - ] - } - ], - "env": [], - "color": "#DDAA99" - }, - { - "id": "6ca1a253.126bb4", - "type": "subflow", - "name": "Acquisition metadata", - "info": "", - "category": "", - "in": [ - { - "x": 50, - "y": 30, - "wires": [ - { - "id": "93a3fd29.c55938" - }, - { - "id": "9e9e7f8a.b66d4" - }, - { - "id": "b1105180.b4b78" - }, - { - "id": "ec403304.e34c58" - }, - { - "id": "7aac5c46.0669ec" - }, - { - "id": "c491cf7.36957b" - }, - { - "id": "e0644195.305068" - }, - { - "id": "e3fe6242.bfaf18" - }, - { - "id": "31d58fcd.ede758" - } - ] - } - ], - "out": [ - { - "x": 740, - "y": 40, - "wires": [ - { - "id": "21b35429.fe43a4", - "port": 0 - }, - { - "id": "f0595ff1.c4d568", - "port": 0 - }, - { - "id": "c4e69883.a0f3d", - "port": 0 - }, - { - "id": "12e818fa.b7301f", - "port": 0 - }, - { - "id": "b577dcd2.8d2c88", - "port": 0 - }, - { - "id": "f7f5ccc1.29a41", - "port": 0 - }, - { - "id": "bd733bef.7efd08", - "port": 0 - }, - { - "id": "a6057924.bc14", - "port": 0 - } - ] - }, - { - "x": 900, - "y": 360, - "wires": [ - { - "id": "5a5fcc9a.9ede14", - "port": 0 - } - ] - } - ], - "env": [], - "color": "#DDAA99" - }, - { - "id": "626459d2.f9c98", - "type": "subflow", - "name": "Pump actuation", - "info": "", - "category": "", - "in": [ - { - "x": 40, - "y": 40, - "wires": [ - { - "id": "f7b6f5e7.7b7ca" - }, - { - "id": "50093f5.8e35ec" - } - ] - } - ], - "out": [ - { - "x": 700, - "y": 40, - "wires": [ - { - "id": "fa485315.928ae", - "port": 0 - }, - { - "id": "2f9ec1a6.d5fb66", - "port": 0 - } - ] - } - ], - "env": [], - "color": "#A6BBCF", - "icon": "font-awesome/fa-recycle" - }, - { - "id": "5c516299.73e054", - "type": "subflow", - "name": "Focus actuation", - "info": "", - "category": "", - "in": [ - { - "x": 40, - "y": 40, - "wires": [ - { - "id": "60dc5851.6962b" - } - ] - } - ], - "out": [ - { - "x": 800, - "y": 200, - "wires": [ - { - "id": "7297e2f7.dce564", - "port": 0 - } - ] - } - ], - "env": [], - "color": "#A6BBCF", - "icon": "node-red/sort.svg" - }, - { - "id": "efeebffd.34c7e", - "type": "subflow", - "name": "Sample metadata", - "info": "", - "category": "", - "in": [ - { - "x": 40, - "y": 40, - "wires": [ - { - "id": "78f5791d.946bd8" - }, - { - "id": "346d141f.ebab3c" - }, - { - "id": "2a09d440.119154" - }, - { - "id": "2d438355.ed942c" - }, - { - "id": "ac4a71a.c35309" - } - ] - } - ], - "out": [ - { - "x": 840, - "y": 40, - "wires": [ - { - "id": "1cb896c7.6dfc11", - "port": 0 - }, - { - "id": "288ba4b3.a9a2cc", - "port": 0 - }, - { - "id": "10f1e5c1.3cb69a", - "port": 0 - }, - { - "id": "aa90b06d.ca78e", - "port": 0 - }, - { - "id": "da0c5a96.74c0e", - "port": 0 - } - ] - } - ], - "env": [], - "color": "#DDAA99" - }, - { - "id": "68d72e45.e7d58", - "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": true, - "reset": false - }, - "darkTheme": { - "default": "#097479", - "baseColor": "#059276", - "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": "#059276", - "edited": true - }, - "page-titlebar-backgroundColor": { - "value": "#059276", - "edited": false - }, - "page-backgroundColor": { - "value": "#111111", - "edited": false - }, - "page-sidebar-backgroundColor": { - "value": "#ffffff", - "edited": false - }, - "group-textColor": { - "value": "#08dcb2", - "edited": false - }, - "group-borderColor": { - "value": "#555555", - "edited": false - }, - "group-backgroundColor": { - "value": "#333333", - "edited": false - }, - "widget-textColor": { - "value": "#eeeeee", - "edited": false - }, - "widget-backgroundColor": { - "value": "#059276", - "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" - } - }, - "site": { - "name": "Node-RED Dashboard", - "hideToolbar": "false", - "allowSwipe": "false", - "lockMenu": "true", - "allowTempTheme": "true", - "dateFormat": "DD/MM/YYYY", - "sizes": { - "sx": 56, - "sy": 56, - "gx": 5, - "gy": 5, - "cx": 5, - "cy": 5, - "px": 5, - "py": 5 - } - } - }, - { - "id": "44986592.b84004", - "type": "mqtt-broker", - "z": "", - "name": "", - "broker": "127.0.0.1", - "port": "1883", - "clientid": "test", - "usetls": false, - "compatmode": false, - "keepalive": "60", - "cleansession": true, - "birthTopic": "", - "birthQos": "0", - "birthPayload": "", - "closeTopic": "", - "closeQos": "0", - "closePayload": "", - "willTopic": "", - "willQos": "0", - "willPayload": "" - }, - { - "id": "8eac3de.7c8234", - "type": "mqtt-broker", - "z": "", - "name": "", - "broker": "0.0.0.0", - "port": "1883", - "clientid": "Client_node", - "usetls": false, - "compatmode": false, - "keepalive": "60", - "cleansession": true, - "birthTopic": "", - "birthQos": "0", - "birthPayload": "", - "closeTopic": "", - "closeQos": "0", - "closePayload": "", - "willTopic": "", - "willQos": "0", - "willPayload": "" - }, - { - "id": "888cbaa1.5d9318", - "type": "mqtt-broker", - "z": "", - "name": "", - "broker": "127.0.0.1", - "port": "1883", - "clientid": "test", - "usetls": false, - "compatmode": false, - "keepalive": "60", - "cleansession": true, - "birthTopic": "", - "birthQos": "0", - "birthPayload": "", - "closeTopic": "", - "closeQos": "0", - "closePayload": "", - "willTopic": "", - "willQos": "0", - "willPayload": "" - }, - { - "id": "f98c50f4.4bed48", - "type": "mqtt-broker", - "z": "", - "name": "", - "broker": "0.0.0.0", - "port": "1883", - "clientid": "Client_node", - "usetls": false, - "compatmode": false, - "keepalive": "60", - "cleansession": true, - "birthTopic": "", - "birthQos": "0", - "birthPayload": "", - "closeTopic": "", - "closeQos": "0", - "closePayload": "", - "willTopic": "", - "willQos": "0", - "willPayload": "" - }, - { - "id": "3ee94635.002c9a", - "type": "mqtt-broker", - "z": "", - "name": "", - "broker": "127.0.0.1", - "port": "1883", - "clientid": "test", - "usetls": false, - "compatmode": false, - "keepalive": "60", - "cleansession": true, - "birthTopic": "", - "birthQos": "0", - "birthPayload": "", - "closeTopic": "", - "closeQos": "0", - "closePayload": "", - "willTopic": "", - "willQos": "0", - "willPayload": "" - }, - { - "id": "b0b1b2bb.385fe", - "type": "mqtt-broker", - "z": "", - "name": "", - "broker": "0.0.0.0", - "port": "1883", - "clientid": "Client_node", - "usetls": false, - "compatmode": false, - "keepalive": "60", - "cleansession": true, - "birthTopic": "", - "birthQos": "0", - "birthPayload": "", - "closeTopic": "", - "closeQos": "0", - "closePayload": "", - "willTopic": "", - "willQos": "0", - "willPayload": "" - }, - { - "id": "659e81f6.f85fb8", - "type": "mqtt-broker", - "z": "", - "name": "", - "broker": "127.0.0.1", - "port": "1883", - "clientid": "test", - "usetls": false, - "compatmode": false, - "keepalive": "60", - "cleansession": true, - "birthTopic": "", - "birthQos": "0", - "birthPayload": "", - "closeTopic": "", - "closeQos": "0", - "closePayload": "", - "willTopic": "", - "willQos": "0", - "willPayload": "" - }, - { - "id": "52b67b31.c63a04", - "type": "mqtt-broker", - "z": "", - "name": "", - "broker": "0.0.0.0", - "port": "1883", - "clientid": "Client_node", - "usetls": false, - "compatmode": false, - "keepalive": "60", - "cleansession": true, - "birthTopic": "", - "birthQos": "0", - "birthPayload": "", - "closeTopic": "", - "closeQos": "0", - "closePayload": "", - "willTopic": "", - "willQos": "0", - "willPayload": "" - }, - { - "id": "494e9f19.80f8e8", - "type": "mqtt-broker", - "z": "", - "name": "", - "broker": "127.0.0.1", - "port": "1883", - "clientid": "test", - "usetls": false, - "compatmode": false, - "keepalive": "60", - "cleansession": true, - "birthTopic": "", - "birthQos": "0", - "birthPayload": "", - "closeTopic": "", - "closeQos": "0", - "closePayload": "", - "willTopic": "", - "willQos": "0", - "willPayload": "" - }, - { - "id": "5ad5df6e.1d1e6", - "type": "mqtt-broker", - "z": "", - "name": "", - "broker": "0.0.0.0", - "port": "1883", - "clientid": "Client_node", - "usetls": false, - "compatmode": false, - "keepalive": "60", - "cleansession": true, - "birthTopic": "", - "birthQos": "0", - "birthPayload": "", - "closeTopic": "", - "closeQos": "0", - "closePayload": "", - "willTopic": "", - "willQos": "0", - "willPayload": "" - }, - { - "id": "3ab46cf0.f57dbc", - "type": "mqtt-broker", - "z": "", - "name": "", - "broker": "127.0.0.1", - "port": "1883", - "clientid": "test", - "usetls": false, - "compatmode": false, - "keepalive": "60", - "cleansession": true, - "birthTopic": "", - "birthQos": "0", - "birthPayload": "", - "closeTopic": "", - "closeQos": "0", - "closePayload": "", - "willTopic": "", - "willQos": "0", - "willPayload": "" - }, - { - "id": "40f247ee.202528", - "type": "mqtt-broker", - "z": "", - "name": "", - "broker": "0.0.0.0", - "port": "1883", - "clientid": "Client_node", - "usetls": false, - "compatmode": false, - "keepalive": "60", - "cleansession": true, - "birthTopic": "", - "birthQos": "0", - "birthPayload": "", - "closeTopic": "", - "closeQos": "0", - "closePayload": "", - "willTopic": "", - "willQos": "0", - "willPayload": "" - }, - { - "id": "84801dc0.193d88", - "type": "mqtt-broker", - "z": "", - "name": "", - "broker": "127.0.0.1", - "port": "1883", - "clientid": "test", - "usetls": false, - "compatmode": false, - "keepalive": "60", - "cleansession": true, - "birthTopic": "", - "birthQos": "0", - "birthPayload": "", - "closeTopic": "", - "closeQos": "0", - "closePayload": "", - "willTopic": "", - "willQos": "0", - "willPayload": "" - }, - { - "id": "e8ab36cc.74d77", - "type": "mqtt-broker", - "z": "", - "name": "", - "broker": "0.0.0.0", - "port": "1883", - "clientid": "Client_node", - "usetls": false, - "compatmode": false, - "keepalive": "60", - "cleansession": true, - "birthTopic": "", - "birthQos": "0", - "birthPayload": "", - "closeTopic": "", - "closeQos": "0", - "closePayload": "", - "willTopic": "", - "willQos": "0", - "willPayload": "" - }, - { - "id": "55588d59.326124", - "type": "ui_group", - "z": "", - "name": "Acquisition actuation", - "tab": "", - "order": 10, - "disp": true, - "width": 24, - "collapse": false - }, - { - "id": "d4efe27d.5af0e", - "type": "ui_group", - "z": "", - "name": "Datetime", - "tab": "", - "order": 1, - "disp": true, - "width": "24", - "collapse": false - }, - { - "id": "4a3b889c.c4c0a", - "type": "ui_group", - "z": "", - "name": "Valve actuation", - "tab": "", - "order": 9, - "disp": true, - "width": "24", - "collapse": false - }, - { - "id": "b2080aa8.7b048", - "type": "ui_group", - "z": "", - "name": "Process metadata", - "tab": "", - "order": 8, - "disp": true, - "width": 24, - "collapse": false - }, - { - "id": "b2ce0fd5.641a8", - "type": "ui_group", - "z": "", - "name": "MQTT Plots", - "tab": "", - "order": 11, - "disp": true, - "width": "24", - "collapse": false - }, - { - "id": "516113d5.b6b5d4", - "type": "ui_group", - "z": "", - "name": "Commands", - "tab": "", - "order": 12, - "disp": true, - "width": 24, - "collapse": false - }, - { - "id": "488da474.92ee5c", - "type": "ui_group", - "z": "", - "name": "Object metadata", - "tab": "", - "order": 6, - "disp": true, - "width": "24", - "collapse": false - }, - { - "id": "a302c12b.834e8", - "type": "ui_group", - "z": "", - "name": "Acquisition metadata", - "tab": "", - "order": 7, - "disp": true, - "width": "24", - "collapse": false - }, - { - "id": "95792df3.55e6e", - "type": "ui_group", - "z": "", - "name": "Pump actuation", - "tab": "", - "order": 5, - "disp": true, - "width": "24", - "collapse": false - }, - { - "id": "8a415d41.11df38", - "type": "ui_group", - "z": "", - "name": "Focus actuation", - "tab": "", - "order": 4, - "disp": true, - "width": "24", - "collapse": false - }, - { - "id": "ead03bfe.db2268", - "type": "ui_group", - "z": "", - "name": "Sample metadata", - "tab": "", - "order": 2, - "disp": true, - "width": "24", - "collapse": false - }, - { - "id": "d4c113ac.dade38", - "type": "ui_group", - "z": "", - "name": "Streaming camera", - "tab": "", - "order": 3, - "disp": true, - "width": 24, - "collapse": false - }, - { - "id": "cdb72118.692578", - "type": "ui_group", - "z": "", - "name": "Acquisition actuation", - "tab": "2b97fe34.a699fa", - "order": 10, - "disp": true, - "width": 24, - "collapse": false - }, - { - "id": "9c86b3b7.54841", - "type": "ui_group", - "z": "", - "name": "Datetime", - "tab": "2b97fe34.a699fa", - "order": 1, - "disp": true, - "width": "24", - "collapse": false - }, - { - "id": "48649115.fcd01", - "type": "ui_group", - "z": "", - "name": "Acquisition inputs", - "tab": "2b97fe34.a699fa", - "order": 9, - "disp": true, - "width": "24", - "collapse": false - }, - { - "id": "beeb994e.b67688", - "type": "ui_group", - "z": "", - "name": "Process metadata", - "tab": "2b97fe34.a699fa", - "order": 8, - "disp": true, - "width": 24, - "collapse": false - }, - { - "id": "eb610eb9.84fae8", - "type": "ui_group", - "z": "", - "name": "MQTT Plots", - "tab": "2b97fe34.a699fa", - "order": 11, - "disp": true, - "width": "24", - "collapse": false - }, - { - "id": "82b3caaa.0518", - "type": "ui_group", - "z": "", - "name": "Commands", - "tab": "2b97fe34.a699fa", - "order": 12, - "disp": true, - "width": 24, - "collapse": false - }, - { - "id": "f377d75b.32d27", - "type": "ui_group", - "z": "", - "name": "Object metadata", - "tab": "2b97fe34.a699fa", - "order": 6, - "disp": true, - "width": "24", - "collapse": false - }, - { - "id": "60b93a5.a032344", - "type": "ui_group", - "z": "", - "name": "Acquisition metadata", - "tab": "2b97fe34.a699fa", - "order": 7, - "disp": true, - "width": "24", - "collapse": false - }, - { - "id": "4153382f.45437", - "type": "ui_group", - "z": "", - "name": "Pump actuation", - "tab": "2b97fe34.a699fa", - "order": 5, - "disp": true, - "width": "24", - "collapse": false - }, - { - "id": "69433259.f306fc", - "type": "ui_group", - "z": "", - "name": "Focus actuation", - "tab": "2b97fe34.a699fa", - "order": 4, - "disp": true, - "width": "24", - "collapse": false - }, - { - "id": "417f91c9.193ab", - "type": "ui_group", - "z": "", - "name": "Sample metadata", - "tab": "2b97fe34.a699fa", - "order": 2, - "disp": true, - "width": "24", - "collapse": false - }, - { - "id": "2b97fe34.a699fa", - "type": "ui_tab", - "z": "", - "name": "GUI", - "icon": "fa-eyedropper", - "order": 2, - "disabled": false, - "hidden": false - }, - { - "id": "dc721eb.9ef51e", - "type": "ui_group", - "z": "", - "name": "Streaming camera", - "tab": "2b97fe34.a699fa", - "order": 3, - "disp": true, - "width": 24, - "collapse": false - }, - { - "id": "853e90d6.4afd1", + "id": "604c996b.1a8428", "type": "ui_button", - "z": "bba19d97.b32b1", + "z": "97600dff.93378", "name": "", "group": "cdb72118.692578", "order": 1, @@ -1169,14 +32,14 @@ "y": 100, "wires": [ [ - "6e46e66c.654ff8" + "b854ad48.5869e8" ] ] }, { - "id": "6e46e66c.654ff8", + "id": "b854ad48.5869e8", "type": "function", - "z": "bba19d97.b32b1", + "z": "97600dff.93378", "name": "image.js", "func": "state = global.get(\"state\");\nglobal.set('img_counter',0)\nglobal.set('obj_counter',0)\nif (state == null){state=\"free\"}\n\nvar sleep_before= global.get(\"custom_sleep_before\");\nvar nb_step= global.get(\"custom_nb_step\");\nvar nb_frame= global.get(\"custom_nb_frame\");\nvar segmentation= global.get(\"custom_segmentation\");\n\nif (sleep_before === undefined || sleep_before === \"\" || sleep_before === null) {\n msg.topic = \"Missing entry :\"\n msg.payload = \"Duration before the acquisition\";\n \n}else if (nb_step === undefined || nb_step === \"\" || nb_step === null) {\n msg.topic = \"Missing entry :\"\n msg.payload = \"Number of step in between two frames\";\n \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 \n}else if (segmentation === undefined || segmentation === \"\" || segmentation === null) {\n msg.topic = \"Missing entry :\"\n msg.payload = \"Realize or not the segmentation\";\n \n}else {\n nb_frame=nb_frame-1\n \n msg.payload=sleep_before+' '+nb_step+' '+nb_frame+' '+segmentation;\n}\nreturn msg;", "outputs": 1, @@ -1185,15 +48,15 @@ "y": 100, "wires": [ [ - "5a37b9e6.6e3e58" + "84505b75.883a48" ] ], "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/PlanktonScope/scripts/focus.py 650 up\n" }, { - "id": "5a37b9e6.6e3e58", + "id": "84505b75.883a48", "type": "switch", - "z": "bba19d97.b32b1", + "z": "97600dff.93378", "name": "", "property": "topic", "propertyType": "msg", @@ -1216,17 +79,17 @@ "y": 100, "wires": [ [ - "75233be8.98e6f4" + "715a8f15.dc211" ], [ - "bee35f80.112d" + "3173806b.bb0c7" ] ] }, { - "id": "bee35f80.112d", + "id": "3173806b.bb0c7", "type": "ui_toast", - "z": "bba19d97.b32b1", + "z": "97600dff.93378", "position": "dialog", "displayTime": "3", "highlight": "", @@ -1244,9 +107,9 @@ ] }, { - "id": "75233be8.98e6f4", + "id": "715a8f15.dc211", "type": "mqtt out", - "z": "bba19d97.b32b1", + "z": "97600dff.93378", "name": "", "topic": "", "qos": "", @@ -1257,9 +120,9 @@ "wires": [] }, { - "id": "75d00421.d31e1c", + "id": "ed689faa.3a3e08", "type": "ui_button", - "z": "bba19d97.b32b1", + "z": "97600dff.93378", "name": "Stop Acquisition", "group": "cdb72118.692578", "order": 2, @@ -1278,14 +141,14 @@ "y": 140, "wires": [ [ - "f2ce7a07.d3eff8" + "f6bd3440.60d5a" ] ] }, { - "id": "f2ce7a07.d3eff8", + "id": "f6bd3440.60d5a", "type": "mqtt out", - "z": "bba19d97.b32b1", + "z": "97600dff.93378", "name": "", "topic": "", "qos": "", @@ -1296,9 +159,9 @@ "wires": [] }, { - "id": "977270e2.b70738", + "id": "3b827bf5.c7bc64", "type": "mqtt out", - "z": "bba19d97.b32b1", + "z": "97600dff.93378", "name": "", "topic": "", "qos": "", @@ -1309,9 +172,44 @@ "wires": [] }, { - "id": "23f3e613.20ad82", + "id": "cdb72118.692578", + "type": "ui_group", + "z": "", + "name": "Acquisition actuation", + "tab": "2b97fe34.a699fa", + "order": 10, + "disp": true, + "width": 24, + "collapse": false + }, + { + "id": "e8320d42.9a3ad8", + "type": "subflow", + "name": "MQQT Cmds", + "info": "", + "category": "", + "in": [ + { + "x": 40, + "y": 40, + "wires": [ + { + "id": "cf9e02a2.3feff" + }, + { + "id": "18da28e6.7b000f" + } + ] + } + ], + "out": [], + "env": [], + "color": "#DDAA99" + }, + { + "id": "a7301ba5.d56d48", "type": "exec", - "z": "c1d3ff7c.4384f", + "z": "e8320d42.9a3ad8", "command": "python3.7 /home/pi/PlanktonScope/script/main.py", "addpay": false, "append": "", @@ -1323,23 +221,23 @@ "y": 140, "wires": [ [ - "87b835dc.107c6", - "2de12b49.050f44" + "87558394.4e589", + "a11158b1.b7649" ], [ - "87b835dc.107c6", - "2de12b49.050f44" + "87558394.4e589", + "a11158b1.b7649" ], [ - "87b835dc.107c6", - "2de12b49.050f44" + "87558394.4e589", + "a11158b1.b7649" ] ] }, { - "id": "1ef92011.66439", + "id": "62b9a3b1.74dbc4", "type": "exec", - "z": "c1d3ff7c.4384f", + "z": "e8320d42.9a3ad8", "command": "ps -ax | grep \"python3.7 /home/pi/PlanktonScope/script/main.py\"| head -1 | awk -F \" \" '{print$1}' ", "addpay": false, "append": "", @@ -1351,16 +249,16 @@ "y": 200, "wires": [ [ - "c1fd2bf6.fa7198" + "66fb9ed2.8ecd3" ], [], [] ] }, { - "id": "c1fd2bf6.fa7198", + "id": "66fb9ed2.8ecd3", "type": "exec", - "z": "c1d3ff7c.4384f", + "z": "e8320d42.9a3ad8", "command": "kill", "addpay": true, "append": "", @@ -1372,23 +270,23 @@ "y": 200, "wires": [ [ - "87b835dc.107c6", - "2de12b49.050f44" + "87558394.4e589", + "a11158b1.b7649" ], [ - "87b835dc.107c6", - "2de12b49.050f44" + "87558394.4e589", + "a11158b1.b7649" ], [ - "87b835dc.107c6", - "2de12b49.050f44" + "87558394.4e589", + "a11158b1.b7649" ] ] }, { - "id": "9a6e378b.5ea938", + "id": "5df162d7.08eb34", "type": "ui_button", - "z": "c1d3ff7c.4384f", + "z": "e8320d42.9a3ad8", "name": "", "group": "9c86b3b7.54841", "order": 9, @@ -1407,14 +305,14 @@ "y": 200, "wires": [ [ - "1ef92011.66439" + "62b9a3b1.74dbc4" ] ] }, { - "id": "e74e7b3d.2ba678", + "id": "d16389e5.3bc67", "type": "ui_button", - "z": "c1d3ff7c.4384f", + "z": "e8320d42.9a3ad8", "name": "", "group": "9c86b3b7.54841", "order": 10, @@ -1433,14 +331,14 @@ "y": 140, "wires": [ [ - "23f3e613.20ad82" + "a7301ba5.d56d48" ] ] }, { - "id": "87b835dc.107c6", + "id": "87558394.4e589", "type": "ui_toast", - "z": "c1d3ff7c.4384f", + "z": "e8320d42.9a3ad8", "position": "top right", "displayTime": "3", "highlight": "", @@ -1456,9 +354,146 @@ "wires": [] }, { - "id": "b60669a0.b480d8", + "id": "500abffa.c7a788", + "type": "file", + "z": "e8320d42.9a3ad8", + "name": "", + "filename": "/home/pi/PlanktonScope/script/main.py", + "appendNewline": false, + "createDir": true, + "overwriteFile": "true", + "encoding": "none", + "x": 530, + "y": 100, + "wires": [ + [ + "a7301ba5.d56d48" + ] + ] + }, + { + "id": "985c65de.0801b", + "type": "template", + "z": "e8320d42.9a3ad8", + "name": "main.py", + "field": "payload", + "fieldType": "msg", + "format": "python", + "syntax": "plain", + "template": "################################################################################\n#Actuator Libraries\n################################################################################\n\n#Library for exchaning messages with Node-RED\nimport paho.mqtt.client as mqtt\n\n#Library to control the PiCamera\nfrom picamera import PiCamera\n\n#Libraries to control the steppers for focusing and pumping\nfrom adafruit_motor import stepper\nfrom adafruit_motorkit import MotorKit\n\n#Library to send command over I2C for the light module on the fan\nimport smbus\n\n################################################################################\n#Practical Libraries\n################################################################################\n\n#Library to get date and time for folder name and filename\nfrom datetime import datetime, timedelta\n\n#Library to be able to sleep for a duration\nfrom time import sleep\n\n#Libraries manipulate json format, execute bash commands\nimport json, shutil, os, subprocess\n\n################################################################################\n#Morphocut Libraries\n################################################################################\n\nfrom skimage.util import img_as_ubyte\nfrom morphocut import Call\nfrom morphocut.contrib.ecotaxa import EcotaxaWriter\nfrom morphocut.contrib.zooprocess import CalculateZooProcessFeatures\nfrom morphocut.core import Pipeline\nfrom morphocut.file import Find\nfrom morphocut.image import (ExtractROI,\n FindRegions,\n ImageReader,\n ImageWriter,\n RescaleIntensity,\n RGB2Gray\n)\nfrom morphocut.stat import RunningMedian\nfrom morphocut.str import Format\nfrom morphocut.stream import TQDM, Enumerate, FilterVariables\n\n################################################################################\n#Other image processing Libraries\n################################################################################\n\nfrom skimage.feature import canny\nfrom skimage.color import rgb2gray, label2rgb\nfrom skimage.morphology import disk\nfrom skimage.morphology import erosion, dilation, closing\nfrom skimage.measure import label, regionprops\nimport cv2\n\n################################################################################\n#Streaming PiCamera over server\n################################################################################\nimport io\nimport picamera\nimport logging\nimport socketserver\nfrom threading import Condition\nfrom http import server\nimport threading\n\n################################################################################\n#Creation of the webpage containing the PiCamera Streaming\n################################################################################\n\nPAGE=\"\"\"\\\n\n\nPlanktonScope v2 | PiCamera Streaming\n\n\n\n\n\n\"\"\"\n\n################################################################################\n#Classes for the PiCamera Streaming\n################################################################################\n\nclass StreamingOutput(object):\n def __init__(self):\n self.frame = None\n self.buffer = io.BytesIO()\n self.condition = Condition()\n\n def write(self, buf):\n if buf.startswith(b'\\xff\\xd8'):\n # New frame, copy the existing buffer's content and notify all\n # clients it's available\n self.buffer.truncate()\n with self.condition:\n self.frame = self.buffer.getvalue()\n self.condition.notify_all()\n self.buffer.seek(0)\n return self.buffer.write(buf)\n\nclass StreamingHandler(server.BaseHTTPRequestHandler):\n def do_GET(self):\n if self.path == '/':\n self.send_response(301)\n self.send_header('Location', '/index.html')\n self.end_headers()\n elif self.path == '/index.html':\n content = PAGE.encode('utf-8')\n self.send_response(200)\n self.send_header('Content-Type', 'text/html')\n self.send_header('Content-Length', len(content))\n self.end_headers()\n self.wfile.write(content)\n elif self.path == '/stream.mjpg':\n self.send_response(200)\n self.send_header('Age', 0)\n self.send_header('Cache-Control', 'no-cache, private')\n self.send_header('Pragma', 'no-cache')\n self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME')\n self.end_headers()\n try:\n while True:\n with output.condition:\n output.condition.wait()\n frame = output.frame\n self.wfile.write(b'--FRAME\\r\\n')\n self.send_header('Content-Type', 'image/jpeg')\n self.send_header('Content-Length', len(frame))\n self.end_headers()\n self.wfile.write(frame)\n self.wfile.write(b'\\r\\n')\n except Exception as e:\n logging.warning(\n 'Removed streaming client %s: %s',\n self.client_address, str(e))\n else:\n self.send_error(404)\n self.end_headers()\n\nclass StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer):\n allow_reuse_address = True\n daemon_threads = True\n\n################################################################################\n#MQTT core functions\n################################################################################\n\n#Run this function in order to connect to the client (Node-RED)\ndef on_connect(client, userdata, flags, rc):\n #Print when connected\n print(\"Connected! - \" + str(rc))\n #When connected, run subscribe()\n client.subscribe(\"actuator/#\")\n #Turn green the light module\n rgb(0,255,0)\n\n#Run this function in order to subscribe to all the topics begining by actuator\ndef on_subscribe(client, obj, mid, granted_qos):\n #Print when subscribed\n print(\"Subscribed! - \"+str(mid)+\" \"+str(granted_qos))\n\n#Run this command when Node-RED is sending a message on the subscribed topic\ndef on_message(client, userdata, msg):\n #Print the topic and the message\n print(msg.topic+\" \"+str(msg.qos)+\" \"+str(msg.payload))\n #Update the global variables command, args and counter\n global command\n global args\n global counter\n #Parse the topic to find the command. ex : actuator/pump -> pump\n command=msg.topic.split(\"/\")[1]\n #Decode the message to find the arguments\n args=str(msg.payload.decode())\n #Reset the counter to 0\n counter=0\n\n################################################################################\n#LEDs Actuation\n################################################################################\ndef rgb(R,G,B):\n #Update LED n1\n bus.write_byte_data(0x0d, 0x00, 0)\n bus.write_byte_data(0x0d, 0x01, R)\n bus.write_byte_data(0x0d, 0x02, G)\n bus.write_byte_data(0x0d, 0x03, B)\n\n #Update LED n2\n bus.write_byte_data(0x0d, 0x00, 1)\n bus.write_byte_data(0x0d, 0x01, R)\n bus.write_byte_data(0x0d, 0x02, G)\n bus.write_byte_data(0x0d, 0x03, B)\n\n #Update LED n3\n bus.write_byte_data(0x0d, 0x00, 2)\n bus.write_byte_data(0x0d, 0x01, R)\n bus.write_byte_data(0x0d, 0x02, G)\n bus.write_byte_data(0x0d, 0x03, B)\n\n #Update the I2C Bus in order to really update the LEDs new values\n cmd=\"i2cdetect -y 1\"\n subprocess.Popen(cmd.split(),stdout=subprocess.PIPE)\n\n################################################################################\n#Init function - executed only once\n################################################################################\n\n#define the bus used to actuate the light module on the fan\nbus = smbus.SMBus(1)\n\n#define the names for the 2 exsting steppers\nkit = MotorKit()\npump_stepper = kit.stepper1\nfocus_stepper = kit.stepper2\n#Make sure the steppers are release and do not use any power\npump_stepper.release()\nfocus_stepper.release()\n\n#Precise the settings of the PiCamera\ncamera = PiCamera()\ncamera.resolution = (3280, 2464)\ncamera.iso = 60\ncamera.shutter_speed = 500\ncamera.exposure_mode = 'fixedfps'\n\n#Declare the global variables command, args and counter\ncommand = ''\nargs = ''\ncounter=''\n\n#MQTT Client functions definition\nclient = mqtt.Client()\nclient.connect(\"192.168.4.1\",1883,60)\nclient.on_connect = on_connect\nclient.on_subscribe = on_subscribe\nclient.on_message = on_message\nclient.loop_start()\n\n################################################################################\n#Definition of the few important metadata\n################################################################################\n\nlocal_metadata = {\n \"process_datetime\": datetime.now(),\n \"acq_camera_resolution\" : camera.resolution,\n \"acq_camera_iso\" : camera.iso,\n \"acq_camera_shutter_speed\" : camera.shutter_speed\n}\n\n#Read the content of config.json containing the metadata defined on Node-RED\nconfig_json = open('/home/pi/PlanktonScope/config.json','r')\nnode_red_metadata = json.loads(config_json.read())\n\n#Concat the local metadata and the metadata from Node-RED\nglobal_metadata = {**local_metadata, **node_red_metadata}\n\n#Define the name of the .zip file that will contain the images and the .tsv table for EcoTaxa\narchive_fn = os.path.join(\"/home/pi/PlanktonScope/\",\"export\", \"ecotaxa_export.zip\")\n\n################################################################################\n#MorphoCut Script\n################################################################################\n\n#Define processing pipeline\nwith Pipeline() as p:\n\n #Recursively find .jpg files in import_path.\n #Sort to get consective frames.\n abs_path = Find(\"/home/pi/PlanktonScope/tmp\", [\".jpg\"], sort=True, verbose=True)\n\n #Extract name from abs_path\n name = Call(lambda p: os.path.splitext(os.path.basename(p))[0], abs_path)\n\n #Set the LEDs as Green\n Call(rgb, 0,255,0)\n\n #Read image\n img = ImageReader(abs_path)\n\n #Show progress bar for frames\n TQDM(Format(\"Frame {name}\", name=name))\n\n #Apply running median to approximate the background image\n flat_field = RunningMedian(img, 5)\n\n #Correct image\n img = img / flat_field\n\n #Rescale intensities and convert to uint8 to speed up calculations\n img = RescaleIntensity(img, in_range=(0, 1.1), dtype=\"uint8\")\n\n #Filter variable to reduce memory load\n FilterVariables(name,img)\n\n #Save cleaned images\n #frame_fn = Format(os.path.join(\"/home/pi/PlanktonScope/tmp\",\"CLEAN\", \"{name}.jpg\"), name=name)\n #ImageWriter(frame_fn, img)\n\n #Convert image to uint8 gray\n img_gray = RGB2Gray(img)\n\n #?\n img_gray = Call(img_as_ubyte, img_gray)\n\n #Canny edge detection using OpenCV\n img_canny = Call(cv2.Canny, img_gray, 50,100)\n\n #Dilate using OpenCV\n kernel = Call(cv2.getStructuringElement, cv2.MORPH_ELLIPSE, (15, 15))\n img_dilate = Call(cv2.dilate, img_canny, kernel, iterations=2)\n\n #Close using OpenCV\n kernel = Call(cv2.getStructuringElement, cv2.MORPH_ELLIPSE, (5, 5))\n img_close = Call(cv2.morphologyEx, img_dilate, cv2.MORPH_CLOSE, kernel, iterations=1)\n\n #Erode using OpenCV\n kernel = Call(cv2.getStructuringElement, cv2.MORPH_ELLIPSE, (15, 15))\n mask = Call(cv2.erode, img_close, kernel, iterations=2)\n\n #Find objects\n regionprops = FindRegions(\n mask, img_gray, min_area=1000, padding=10, warn_empty=name\n )\n\n #Set the LEDs as Purple\n Call(rgb, 255,0,255)\n\n # For an object, extract a vignette/ROI from the image\n roi_orig = ExtractROI(img, regionprops, bg_color=255)\n\n # Generate an object identifier\n i = Enumerate()\n\n #Call(print,i)\n\n #Define the ID of each object\n object_id = Format(\"{name}_{i:d}\", name=name, i=i)\n\n #Call(print,object_id)\n\n #Define the name of each object\n object_fn = Format(os.path.join(\"/home/pi/PlanktonScope/\",\"OBJECTS\", \"{name}.jpg\"), name=object_id)\n\n #Save the image of the object with its name\n ImageWriter(object_fn, roi_orig)\n\n #Calculate features. The calculated features are added to the global_metadata.\n #Returns a Variable representing a dict for every object in the stream.\n meta = CalculateZooProcessFeatures(\n regionprops, prefix=\"object_\", meta=global_metadata\n )\n\n #Get all the metadata\n json_meta = Call(json.dumps,meta, sort_keys=True, default=str)\n\n #Publish the json containing all the metadata to via MQTT to Node-RED\n Call(client.publish, \"receiver/segmentation/metric\", json_meta)\n\n #Add object_id to the metadata dictionary\n meta[\"object_id\"] = object_id\n\n #Generate object filenames\n orig_fn = Format(\"{object_id}.jpg\", object_id=object_id)\n\n #Write objects to an EcoTaxa archive:\n #roi image in original color, roi image in grayscale, metadata associated with each object\n EcotaxaWriter(archive_fn, (orig_fn, roi_orig), meta)\n\n #Progress bar for objects\n TQDM(Format(\"Object {object_id}\", object_id=object_id))\n\n #Publish the object_id to via MQTT to Node-RED\n Call(client.publish, \"receiver/segmentation/object_id\", object_id)\n\n #Set the LEDs as Green\n Call(rgb, 0,255,0)\n\n################################################################################\n#While loop for capting commands from Node-RED\n################################################################################\n\noutput = StreamingOutput()\naddress = ('192.168.4.1', 8000)\nserver = StreamingServer(address, StreamingHandler)\nthreading.Thread(target=server.serve_forever).start()\ncamera.start_recording(output, format='mjpeg', resize=(640, 480))\n\nwhile True:\n\n ############################################################################\n #Pump Event\n ############################################################################\n\n #If the command is \"pump\"\n if (command==\"pump\"):\n\n #Set the LEDs as Blue\n rgb(0,0,255)\n\n #Get direction from the different received arguments\n direction=args.split(\" \")[0]\n\n #Get delay (in between steps) from the different received arguments\n delay=float(args.split(\" \")[1])\n\n #Get number of steps from the different received arguments\n nb_step=int(args.split(\" \")[2])\n\n #Print status\n print(\"The pump has been started.\")\n\n #Publish the status \"Start\" to via MQTT to Node-RED\n client.publish(\"receiver/pump\", \"Start\");\n\n ########################################################################\n while True:\n\n #Depending on direction, select the right direction for the pump\n if direction == \"BACKWARD\":\n direction=stepper.BACKWARD\n\n if direction == \"FORWARD\":\n direction=stepper.FORWARD\n\n #Actuate the pump for one step in the right direction\n pump_stepper.onestep(direction=direction, style=stepper.DOUBLE)\n\n #Increment the counter\n counter+=1\n\n #Wait during the delay to pump at the right flowrate\n sleep(delay)\n\n ####################################################################\n #If counter reach the number of step, break\n if counter>nb_step:\n\n #Release the pump stepper to stop power draw\n pump_stepper.release()\n\n #Print status\n print(\"The pumping is done.\")\n\n #Change the command to not re-enter in this while loop\n command=\"wait\"\n\n #Publish the status \"Done\" to via MQTT to Node-RED\n client.publish(\"receiver/pump\", \"Done\");\n\n #Set the LEDs as Green\n rgb(0,255,0)\n\n #Reset the counter to 0\n counter=0\n\n break\n\n ####################################################################\n #If a new received command isn't \"pump\", break this while loop\n if command!=\"pump\":\n\n #Release the pump stepper to stop power draw\n pump_stepper.release()\n\n #Print status\n print(\"The pump has been interrompted.\")\n\n #Publish the status \"Interrompted\" to via MQTT to Node-RED\n client.publish(\"receiver/pump\", \"Interrompted\");\n\n #Set the LEDs as Green\n rgb(0,255,0)\n\n #Reset the counter to 0\n counter=0\n\n break\n\n ############################################################################\n #Focus Event\n ############################################################################\n\n #If the command is \"focus\"\n elif (command==\"focus\"):\n\n #Set the LEDs as Yellow\n rgb(255,255,0)\n\n #Get direction from the different received arguments\n direction=args.split(\" \")[0]\n\n #Get number of steps from the different received arguments\n nb_step=int(args.split(\" \")[1])\n\n #Print status\n print(\"The focus has been started.\")\n\n #Publish the status \"Start\" to via MQTT to Node-RED\n client.publish(\"receiver/focus\", \"Start\");\n\n ########################################################################\n while True:\n\n #Depending on direction, select the right direction for the focus\n if direction == \"FORWARD\":\n direction=stepper.FORWARD\n\n if direction == \"BACKWARD\":\n direction=stepper.BACKWARD\n\n #Actuate the focus for one microstep in the right direction\n focus_stepper.onestep(direction=direction, style=stepper.MICROSTEP)\n\n #Increment the counter\n counter+=1\n\n ####################################################################\n #If counter reach the number of step, break\n if counter>nb_step:\n\n #Release the focus steppers to stop power draw\n focus_stepper.release()\n\n #Print status\n print(\"The focusing is done.\")\n\n #Change the command to not re-enter in this while loop\n command=\"wait\"\n\n #Publish the status \"Done\" to via MQTT to Node-RED\n client.publish(\"receiver/focus\", \"Done\");\n\n #Set the LEDs as Green\n rgb(0,255,0)\n\n #Reset the counter to 0\n counter=0\n\n break\n\n ####################################################################\n #If a new received command isn't \"pump\", break this while loop\n if command!=\"focus\":\n\n #Release the focus steppers to stop power draw\n focus_stepper.release()\n\n #Print status\n print(\"The stage has been interrompted.\")\n\n #Publish the status \"Done\" to via MQTT to Node-RED\n client.publish(\"receiver/focus\", \"Interrompted\");\n\n #Set the LEDs as Green\n rgb(0,255,0)\n\n #Reset the counter to 0\n counter=0\n\n break\n\n ############################################################################\n #Image Event\n ############################################################################\n\n elif (command==\"image\"):\n \n #Publish the status \"Start\" to via MQTT to Node-RED\n client.publish(\"receiver/image\", \"Will do my best dude\");\n\n #Get duration to wait before an image from the different received arguments\n sleep_before=int(args.split(\" \")[0])\n\n #Get number of step in between two images from the different received arguments\n nb_step=int(args.split(\" \")[1])\n\n #Get the number of frames to image from the different received arguments\n nb_frame=int(args.split(\" \")[2])\n\n #Get the segmentation status (true/false) from the different received arguments\n segmentation=str(args.split(\" \")[3])\n\n #Sleep a duration before to start acquisition\n sleep(sleep_before)\n\n #Publish the status \"Start\" to via MQTT to Node-RED\n client.publish(\"receiver/image\", \"Start\");\n\n #Set the LEDs as Blue\n rgb(0,0,255)\n\n #Pump duing a given number of steps (in between each image)\n for i in range(nb_step):\n\n #If the command is still image - pump a defined nb of steps\n if (command==\"image\"):\n\n #Actuate the pump for one step in the FORWARD direction\n pump_stepper.onestep(direction=stepper.FORWARD, style=stepper.DOUBLE)\n\n #The flowrate is fixed for now.\n sleep(0.01)\n\n #If the command isn't image anymore - break\n else:\n\n break\n\n #Set the LEDs as Green\n rgb(0,255,0)\n\n while True:\n\n #Set the LEDs as Cyan\n rgb(0,255,255)\n\n #Increment the counter\n counter+=1\n\n #Get datetime\n datetime_tmp=datetime.now().strftime(\"%H_%M_%S_%f\")\n\n #Print datetime\n print(datetime_tmp)\n\n #Define the filename of the image\n filename = os.path.join(\"/home/pi/PlanktonScope/tmp\",datetime_tmp+\".jpg\")\n\n #Capture an image with the proper filename\n camera.capture(filename)\n\n #Set the LEDs as Green\n rgb(0,255,0)\n\n #Publish the name of the image to via MQTT to Node-RED\n\n client.publish(\"receiver/image\", datetime_tmp+\".jpg has been imaged.\");\n \n #Set the LEDs as Blue\n rgb(0,0,255)\n\n #Pump during a given nb of steps\n for i in range(nb_step):\n\n #Actuate the pump for one step in the FORWARD direction\n pump_stepper.onestep(direction=stepper.FORWARD, style=stepper.DOUBLE)\n\n #The flowrate is fixed for now.\n sleep(0.01)\n\n #Wait a fixed delay which set the framerate as < than 2 imag/sec\n sleep(0.5)\n\n #Set the LEDs as Green\n rgb(0,255,0)\n\n ####################################################################\n #If counter reach the number of frame, break\n if(counter>nb_frame):\n\n #Publish the status \"Completed\" to via MQTT to Node-RED\n client.publish(\"receiver/image\", \"Completed\");\n\n #Release the pump steppers to stop power draw\n pump_stepper.release()\n\n if(segmentation == \"True\"):\n\n #Publish the status \"Start\" to via MQTT to Node-RED\n client.publish(\"receiver/segmentation\", \"Start\");\n\n #Start the MorphoCut Pipeline\n p.run()\n\n #remove directory\n #shutil.rmtree(import_path)\n\n #Publish the status \"Completed\" to via MQTT to Node-RED\n client.publish(\"receiver/segmentation\", \"Completed\");\n\n #Set the LEDs as White\n rgb(255,255,255)\n\n #cmd = os.popen(\"rm -rf /home/pi/PlanktonScope/tmp/*.jpg\")\n\n #Let it happen\n sleep(1)\n\n #Set the LEDs as Green\n rgb(0,255,0)\n\n #End if(segmentation == \"True\"):\n\n #Change the command to not re-enter in this while loop\n command=\"wait\"\n \n #Set the LEDs as Green\n rgb(0,255,255)\n\n #Reset the counter to 0\n counter=0\n\n break\n\n ####################################################################\n #If a new received command isn't \"image\", break this while loop\n if command!=\"image\":\n\n #Release the pump steppers to stop power draw\n pump_stepper.release()\n\n #Print status\n print(\"The imaging has been interrompted.\")\n\n #Publish the status \"Interrompted\" to via MQTT to Node-RED\n client.publish(\"receiver/image\", \"Interrompted\");\n\n #Set the LEDs as Green\n rgb(0,255,0)\n\n #Reset the counter to 0\n counter=0\n\n break\n\n else:\n #Set the LEDs as Black\n rgb(0,0,0)\n #Its just waiting to receive command from Node-RED\n sleep(1)\n #Set the LEDs as White\n rgb(255,255,255)\n #Its just waiting to receive command from Node-RED\n sleep(1)\n", + "output": "str", + "x": 300, + "y": 100, + "wires": [ + [ + "500abffa.c7a788" + ] + ] + }, + { + "id": "a11158b1.b7649", + "type": "debug", + "z": "e8320d42.9a3ad8", + "name": "", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "x": 1230, + "y": 200, + "wires": [] + }, + { + "id": "cf9e02a2.3feff", "type": "exec", - "z": "c10e968b.87e488", + "z": "e8320d42.9a3ad8", + "command": "ps -ax | grep \"python3.7 /home/pi/PlanktonScope/script/main.py\"| head -1 | awk -F \" \" '{print$1}' ", + "addpay": false, + "append": "", + "useSpawn": "false", + "timer": "", + "oldrc": false, + "name": "", + "x": 430, + "y": 40, + "wires": [ + [ + "945415c5.01217" + ], + [], + [] + ] + }, + { + "id": "945415c5.01217", + "type": "exec", + "z": "e8320d42.9a3ad8", + "command": "kill", + "addpay": true, + "append": "", + "useSpawn": "false", + "timer": "", + "oldrc": false, + "name": "", + "x": 910, + "y": 40, + "wires": [ + [], + [], + [] + ] + }, + { + "id": "18da28e6.7b000f", + "type": "delay", + "z": "e8320d42.9a3ad8", + "name": "", + "pauseType": "delay", + "timeout": "1", + "timeoutUnits": "seconds", + "rate": "1", + "nbRateUnits": "1", + "rateUnits": "second", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": false, + "x": 160, + "y": 100, + "wires": [ + [ + "985c65de.0801b" + ] + ] + }, + { + "id": "6384a5e.e34465c", + "type": "subflow", + "name": "Datetime update", + "info": "", + "category": "", + "in": [ + { + "x": 140, + "y": 80, + "wires": [ + { + "id": "42ffcda3.49c30c" + } + ] + } + ], + "out": [], + "env": [], + "color": "#DDAA99", + "icon": "font-awesome/fa-clock-o" + }, + { + "id": "e3824a97.8f2c3", + "type": "exec", + "z": "6384a5e.e34465c", "command": "sudo date -s", "addpay": true, "append": "", @@ -1475,9 +510,9 @@ ] }, { - "id": "68aace8d.6bf5", + "id": "a5a13db6.4c6958", "type": "function", - "z": "c10e968b.87e488", + "z": "6384a5e.e34465c", "name": "", "func": "d = new Date();\n//get weekday\nvar weekday = new Array(7);\nweekday[0] = \"Sun\";\nweekday[1] = \"Mon\";\nweekday[2] = \"Tue\";\nweekday[3] = \"Wed\";\nweekday[4] = \"Thu\";\nweekday[5] = \"Fri\";\nweekday[6] = \"Sat\";\nvar w = weekday[d.getUTCDay()];\n//get Month\nvar month = new Array(12);\nmonth[0] = \"Jan\";\nmonth[1] = \"Feb\";\nmonth[2] = \"Mar\";\nmonth[3] = \"Apr\";\nmonth[4] = \"May\";\nmonth[5] = \"Jun\";\nmonth[6] = \"Jul\";\nmonth[7] = \"Aug\";\nmonth[8] = \"Sep\";\nmonth[9] = \"Oct\";\nmonth[10] = \"Nov\";\nmonth[11] = \"Dec\";\nvar n = month[d.getUTCMonth()];\n \n//get day\nvar day = d.getUTCDay()\n\n//get Hours\nvar Hours = d.getUTCHours();\n//get Minutes\nvar Minutes = d.getUTCMinutes();\n//get Seconds\nvar Seconds = d.getUTCSeconds();\n//get FullYear\nvar FullYear = d.getUTCFullYear();\n\n//Thu Aug 09 2012 23:34:04 GMT+0200 (GMT+02:00)\n\n//Thu Aug 9 21:31:26 UTC 2012\n\n//msg.payload = \"Thu Aug 9 21:31:26 UTC 2012\"\n\nmsg.payload = '\"'+w+\" \"+n+\" \"+day+\" \"+Hours+\":\"+Minutes+\":\"+Seconds+\" UTC \"+FullYear+'\"';\nreturn msg;", "outputs": 1, @@ -1486,14 +521,14 @@ "y": 40, "wires": [ [ - "a1db5dbb.32c998" + "bafb69f.a42ea18" ] ] }, { - "id": "a1db5dbb.32c998", + "id": "bafb69f.a42ea18", "type": "ui_template", - "z": "c10e968b.87e488", + "z": "6384a5e.e34465c", "group": "9c86b3b7.54841", "name": "", "order": 1, @@ -1510,9 +545,9 @@ ] }, { - "id": "b3b03af9.8edae8", + "id": "81f9cd4c.8540b", "type": "ui_numeric", - "z": "c10e968b.87e488", + "z": "6384a5e.e34465c", "name": "tmp_year", "label": "Year", "tooltip": "", @@ -1531,14 +566,14 @@ "y": 80, "wires": [ [ - "8de4b398.3c755" + "8f5a74df.0663f" ] ] }, { - "id": "ed1f72c4.e136e", + "id": "274f25fc.9e61ba", "type": "ui_numeric", - "z": "c10e968b.87e488", + "z": "6384a5e.e34465c", "name": "tmp_month", "label": "Month", "tooltip": "", @@ -1557,14 +592,14 @@ "y": 120, "wires": [ [ - "8de4b398.3c755" + "8f5a74df.0663f" ] ] }, { - "id": "be55a4d1.4d5fa8", + "id": "4ddcb673.905a", "type": "ui_numeric", - "z": "c10e968b.87e488", + "z": "6384a5e.e34465c", "name": "tmp_day", "label": "Day", "tooltip": "", @@ -1583,14 +618,14 @@ "y": 160, "wires": [ [ - "8de4b398.3c755" + "8f5a74df.0663f" ] ] }, { - "id": "ee1e92f8.a01bb8", + "id": "248eee4c.238282", "type": "ui_numeric", - "z": "c10e968b.87e488", + "z": "6384a5e.e34465c", "name": "tmp_hour", "label": "Hour", "tooltip": "", @@ -1609,14 +644,14 @@ "y": 200, "wires": [ [ - "8de4b398.3c755" + "8f5a74df.0663f" ] ] }, { - "id": "c532a0cd.b0a47", + "id": "a368c4b7.2dc4b8", "type": "ui_numeric", - "z": "c10e968b.87e488", + "z": "6384a5e.e34465c", "name": "tmp_minute", "label": "Minute", "tooltip": "", @@ -1635,14 +670,14 @@ "y": 240, "wires": [ [ - "8de4b398.3c755" + "8f5a74df.0663f" ] ] }, { - "id": "5b200123.04ec98", + "id": "96cc9953.9496c8", "type": "ui_numeric", - "z": "c10e968b.87e488", + "z": "6384a5e.e34465c", "name": "tmp_second", "label": "Second", "tooltip": "", @@ -1661,14 +696,14 @@ "y": 280, "wires": [ [ - "8de4b398.3c755" + "8f5a74df.0663f" ] ] }, { - "id": "d8f0f8d1.0550d", + "id": "d6240495.8429c", "type": "interval", - "z": "c10e968b.87e488", + "z": "6384a5e.e34465c", "name": "interval", "interval": "1", "onstart": false, @@ -1680,14 +715,14 @@ "y": 40, "wires": [ [ - "68aace8d.6bf5" + "a5a13db6.4c6958" ] ] }, { - "id": "eb163e1c.a7b97", + "id": "e8d38dc0.c7e84", "type": "ui_button", - "z": "c10e968b.87e488", + "z": "6384a5e.e34465c", "name": "", "group": "9c86b3b7.54841", "order": 8, @@ -1706,14 +741,14 @@ "y": 320, "wires": [ [ - "aa948c91.3895a" + "581f71d3.bde458" ] ] }, { - "id": "aa948c91.3895a", + "id": "581f71d3.bde458", "type": "function", - "z": "c10e968b.87e488", + "z": "6384a5e.e34465c", "name": "update datetime", "func": "var FullYear= global.get(\"year\");\nvar Month= global.get(\"month\");\nvar day= global.get(\"day\");\nvar Hours= global.get(\"hour\");\nvar Minutes= global.get(\"minute\");\nvar Seconds= global.get(\"second\");\n\nmsg.payload = new Date();\n//get Month\nvar month = new Array(12);\nmonth[1] = \"Jan\";\nmonth[2] = \"Feb\";\nmonth[3] = \"Mar\";\nmonth[4] = \"Apr\";\nmonth[5] = \"May\";\nmonth[6] = \"Jun\";\nmonth[7] = \"Jul\";\nmonth[8] = \"Aug\";\nmonth[9] = \"Sep\";\nmonth[10] = \"Oct\";\nmonth[11] = \"Nov\";\nmonth[12] = \"Dec\";\nvar n = month[Month];\n \nmsg.payload = '\"'+day+\" \"+n+\" \"+FullYear+\" \"+Hours+\":\"+Minutes+\":\"+Seconds+'\"';\n\n\nreturn msg;", "outputs": 1, @@ -1722,15 +757,15 @@ "y": 320, "wires": [ [ - "3b7403cb.d33394", - "b60669a0.b480d8" + "6b023a67.faa104", + "e3824a97.8f2c3" ] ] }, { - "id": "8de4b398.3c755", + "id": "8f5a74df.0663f", "type": "function", - "z": "c10e968b.87e488", + "z": "6384a5e.e34465c", "name": "set global", "func": "var value = msg.payload;\nvar key = msg.topic;\n\nglobal.set(key,value);\nreturn msg;", "outputs": 1, @@ -1742,9 +777,9 @@ ] }, { - "id": "3b7403cb.d33394", + "id": "6b023a67.faa104", "type": "debug", - "z": "c10e968b.87e488", + "z": "6384a5e.e34465c", "name": "", "active": true, "tosidebar": true, @@ -1756,9 +791,9 @@ "wires": [] }, { - "id": "315c5aa3.fdf5d6", + "id": "4ab089b9.1098", "type": "function", - "z": "c10e968b.87e488", + "z": "6384a5e.e34465c", "name": "", "func": "d = msg.payload;\n\nvar val = d.getUTCFullYear();\n\nmsg.payload = val;\nreturn msg;", "outputs": 1, @@ -1767,14 +802,14 @@ "y": 80, "wires": [ [ - "b3b03af9.8edae8" + "81f9cd4c.8540b" ] ] }, { - "id": "93b9f3cd.759688", + "id": "42ffcda3.49c30c", "type": "function", - "z": "c10e968b.87e488", + "z": "6384a5e.e34465c", "name": "", "func": "d = new Date();\nmsg.payload = d\nreturn msg;", "outputs": 1, @@ -1783,19 +818,19 @@ "y": 80, "wires": [ [ - "315c5aa3.fdf5d6", - "922cecc2.dc7f68", - "c2aa11f2.0fdee8", - "915b7162.7a73e", - "b57fe145.320d28", - "d3f45b98.f05a58" + "4ab089b9.1098", + "13529b2c.cb9d9d", + "c09bb768.0e7518", + "967b4488.670f08", + "3e3732d.273a04e", + "327729f0.afe466" ] ] }, { - "id": "922cecc2.dc7f68", + "id": "13529b2c.cb9d9d", "type": "function", - "z": "c10e968b.87e488", + "z": "6384a5e.e34465c", "name": "", "func": "d = msg.payload;\n\nvar val = d.getUTCMonth();\n\nmsg.payload = val+1;\nreturn msg;", "outputs": 1, @@ -1804,14 +839,14 @@ "y": 120, "wires": [ [ - "ed1f72c4.e136e" + "274f25fc.9e61ba" ] ] }, { - "id": "c2aa11f2.0fdee8", + "id": "c09bb768.0e7518", "type": "function", - "z": "c10e968b.87e488", + "z": "6384a5e.e34465c", "name": "", "func": "d = msg.payload;\n\nvar val = d.getUTCDay();\n\nmsg.payload = val;\nreturn msg;", "outputs": 1, @@ -1820,14 +855,14 @@ "y": 160, "wires": [ [ - "be55a4d1.4d5fa8" + "4ddcb673.905a" ] ] }, { - "id": "915b7162.7a73e", + "id": "967b4488.670f08", "type": "function", - "z": "c10e968b.87e488", + "z": "6384a5e.e34465c", "name": "", "func": "d = msg.payload;\n\nvar val = d.getUTCHours();\n\nmsg.payload = val;\nreturn msg;", "outputs": 1, @@ -1836,14 +871,14 @@ "y": 200, "wires": [ [ - "ee1e92f8.a01bb8" + "248eee4c.238282" ] ] }, { - "id": "b57fe145.320d28", + "id": "3e3732d.273a04e", "type": "function", - "z": "c10e968b.87e488", + "z": "6384a5e.e34465c", "name": "", "func": "d = msg.payload;\n\nvar val = d.getUTCMinutes();\n\nmsg.payload = val;\nreturn msg;", "outputs": 1, @@ -1852,14 +887,14 @@ "y": 240, "wires": [ [ - "c532a0cd.b0a47" + "a368c4b7.2dc4b8" ] ] }, { - "id": "d3f45b98.f05a58", + "id": "327729f0.afe466", "type": "function", - "z": "c10e968b.87e488", + "z": "6384a5e.e34465c", "name": "", "func": "d = msg.payload;\n\nvar val = d.getUTCSeconds();\n\nmsg.payload = val;\nreturn msg;", "outputs": 1, @@ -1868,14 +903,79 @@ "y": 280, "wires": [ [ - "5b200123.04ec98" + "96cc9953.9496c8" ] ] }, { - "id": "c4527705.33a84", + "id": "9c86b3b7.54841", + "type": "ui_group", + "z": "", + "name": "Datetime", + "tab": "2b97fe34.a699fa", + "order": 1, + "disp": true, + "width": "24", + "collapse": false + }, + { + "id": "a156df1e.d37178", + "type": "subflow", + "name": "Acquisition inputs", + "info": "", + "category": "", + "in": [ + { + "x": 40, + "y": 40, + "wires": [ + { + "id": "2dd27be1.476eac" + }, + { + "id": "3883d084.feb708" + }, + { + "id": "4bf1038f.d36f9c" + }, + { + "id": "ae15c276.ec8c68" + } + ] + } + ], + "out": [ + { + "x": 740, + "y": 40, + "wires": [ + { + "id": "b996437b.1a45b8", + "port": 0 + }, + { + "id": "d56a51c1.60023", + "port": 0 + }, + { + "id": "229ade87.b1656a", + "port": 0 + }, + { + "id": "5e093b67.a32f9c", + "port": 0 + } + ] + } + ], + "env": [], + "color": "#A6BBCF", + "icon": "node-red-contrib-camerapi/photo.png" + }, + { + "id": "b996437b.1a45b8", "type": "ui_text_input", - "z": "863e8384.56889", + "z": "a156df1e.d37178", "name": "custom_nb_step", "label": "Number of steps in between two images", "tooltip": "", @@ -1894,9 +994,9 @@ ] }, { - "id": "582e21b2.ad67a8", + "id": "229ade87.b1656a", "type": "ui_text_input", - "z": "863e8384.56889", + "z": "a156df1e.d37178", "name": "custom_nb_frame", "label": "Number of images per acquisition", "tooltip": "", @@ -1915,9 +1015,9 @@ ] }, { - "id": "3eaf4c98.d94b54", + "id": "2dd27be1.476eac", "type": "function", - "z": "863e8384.56889", + "z": "a156df1e.d37178", "name": "get custom_nb_step", "func": "msg.payload = msg.payload.custom_nb_step;\nreturn msg;", "outputs": 1, @@ -1926,14 +1026,14 @@ "y": 80, "wires": [ [ - "c4527705.33a84" + "b996437b.1a45b8" ] ] }, { - "id": "8eeb9e9e.a50d7", + "id": "4bf1038f.d36f9c", "type": "function", - "z": "863e8384.56889", + "z": "a156df1e.d37178", "name": "get custom_nb_frame", "func": "msg.payload = msg.payload.custom_nb_frame;\nreturn msg;", "outputs": 1, @@ -1942,14 +1042,14 @@ "y": 120, "wires": [ [ - "582e21b2.ad67a8" + "229ade87.b1656a" ] ] }, { - "id": "e4e16eb9.5296c", + "id": "ae15c276.ec8c68", "type": "function", - "z": "863e8384.56889", + "z": "a156df1e.d37178", "name": "get custom_segmentation", "func": "msg.payload = msg.payload.custom_segmentation;\nreturn msg;", "outputs": 1, @@ -1958,14 +1058,14 @@ "y": 160, "wires": [ [ - "f9705bc.3d322a8" + "5e093b67.a32f9c" ] ] }, { - "id": "e50aa637.59ac68", + "id": "3883d084.feb708", "type": "function", - "z": "863e8384.56889", + "z": "a156df1e.d37178", "name": "get custom_sleep_before", "func": "msg.payload = msg.payload.custom_sleep_before;\nreturn msg;", "outputs": 1, @@ -1974,14 +1074,14 @@ "y": 40, "wires": [ [ - "f648e44.94e3998" + "d56a51c1.60023" ] ] }, { - "id": "f648e44.94e3998", + "id": "d56a51c1.60023", "type": "ui_text_input", - "z": "863e8384.56889", + "z": "a156df1e.d37178", "name": "custom_sleep_before", "label": "Duration before the acquisition (s)", "tooltip": "", @@ -2000,9 +1100,81 @@ ] }, { - "id": "11b31baf.95996c", + "id": "5e093b67.a32f9c", + "type": "ui_switch", + "z": "a156df1e.d37178", + "name": "custom_segmentation", + "label": "Realize the segmentation", + "tooltip": "", + "group": "48649115.fcd01", + "order": 6, + "width": 0, + "height": 0, + "passthru": true, + "decouple": "false", + "topic": "custom_segmentation", + "style": "", + "onvalue": "True", + "onvalueType": "str", + "onicon": "", + "oncolor": "", + "offvalue": "False", + "offvalueType": "str", + "officon": "", + "offcolor": "", + "x": 520, + "y": 160, + "wires": [ + [] + ] + }, + { + "id": "48649115.fcd01", + "type": "ui_group", + "z": "", + "name": "Acquisition inputs", + "tab": "2b97fe34.a699fa", + "order": 9, + "disp": true, + "width": "24", + "collapse": false + }, + { + "id": "99798a85.e62408", + "type": "subflow", + "name": "Process metadata", + "info": "", + "category": "", + "in": [ + { + "x": 40, + "y": 80, + "wires": [ + { + "id": "20414296.54837e" + } + ] + } + ], + "out": [ + { + "x": 700, + "y": 80, + "wires": [ + { + "id": "d5ab9061.b06a9", + "port": 0 + } + ] + } + ], + "env": [], + "color": "#DDAA99" + }, + { + "id": "d5ab9061.b06a9", "type": "ui_text_input", - "z": "5a287804.a10e2", + "z": "99798a85.e62408", "name": "process_id", "label": "Id of the process", "tooltip": "", @@ -2021,9 +1193,9 @@ ] }, { - "id": "dfb4b682.601e1", + "id": "20414296.54837e", "type": "function", - "z": "5a287804.a10e2", + "z": "99798a85.e62408", "name": "get process_id", "func": "msg.payload = msg.payload.process_id+1;\nreturn msg;", "outputs": 1, @@ -2032,14 +1204,37 @@ "y": 80, "wires": [ [ - "11b31baf.95996c" + "d5ab9061.b06a9" ] ] }, { - "id": "3777e513.35c3fa", + "id": "beeb994e.b67688", + "type": "ui_group", + "z": "", + "name": "Process metadata", + "tab": "2b97fe34.a699fa", + "order": 8, + "disp": true, + "width": 24, + "collapse": false + }, + { + "id": "246abd43.838a5a", + "type": "subflow", + "name": "MQTT Receive & Plot", + "info": "", + "category": "", + "in": [], + "out": [], + "env": [], + "color": "#F3B567", + "icon": "node-red/bridge.svg" + }, + { + "id": "1aeca49c.10b893", "type": "mqtt in", - "z": "a8ad6dec.1a393", + "z": "246abd43.838a5a", "name": "", "topic": "receiver/#", "qos": "0", @@ -2049,15 +1244,15 @@ "y": 40, "wires": [ [ - "9886f960.4b6268", - "589fbae2.8ff914" + "be5de01e.45d56", + "613bee5b.042fe" ] ] }, { - "id": "9886f960.4b6268", + "id": "be5de01e.45d56", "type": "switch", - "z": "a8ad6dec.1a393", + "z": "246abd43.838a5a", "name": "", "property": "topic", "propertyType": "msg", @@ -2090,23 +1285,23 @@ "y": 40, "wires": [ [ - "c90e948f.2f7348" + "d39289fb.9f759" ], [ - "1d54f7b3.db7ac8" + "e2ab3af3.e61a8" ], [ - "d02a7968.b8874" + "e43e94c.c297968" ], [ - "11e60fef.079d38" + "b06c80f3.f1642" ] ] }, { - "id": "c90e948f.2f7348", + "id": "d39289fb.9f759", "type": "switch", - "z": "a8ad6dec.1a393", + "z": "246abd43.838a5a", "name": "", "property": "payload", "propertyType": "msg", @@ -2134,20 +1329,20 @@ "y": 40, "wires": [ [ - "e16b8120.403e8" + "267bd959.17b856" ], [ - "4ea155a3.d8531c" + "265e58c6.06de38" ], [ - "3d35b841.e6596" + "a433c901.2abd48" ] ] }, { - "id": "e16b8120.403e8", + "id": "267bd959.17b856", "type": "change", - "z": "a8ad6dec.1a393", + "z": "246abd43.838a5a", "name": "The pump has started", "rules": [ { @@ -2167,14 +1362,14 @@ "y": 40, "wires": [ [ - "1597b08f.5bce8f" + "3b6b4fd4.8c3368" ] ] }, { - "id": "4ea155a3.d8531c", + "id": "265e58c6.06de38", "type": "change", - "z": "a8ad6dec.1a393", + "z": "246abd43.838a5a", "name": "The pump has finished.", "rules": [ { @@ -2194,14 +1389,14 @@ "y": 80, "wires": [ [ - "1597b08f.5bce8f" + "3b6b4fd4.8c3368" ] ] }, { - "id": "3d35b841.e6596", + "id": "a433c901.2abd48", "type": "change", - "z": "a8ad6dec.1a393", + "z": "246abd43.838a5a", "name": "The pump has been stopped.", "rules": [ { @@ -2221,14 +1416,14 @@ "y": 120, "wires": [ [ - "1597b08f.5bce8f" + "3b6b4fd4.8c3368" ] ] }, { - "id": "1d54f7b3.db7ac8", + "id": "e2ab3af3.e61a8", "type": "switch", - "z": "a8ad6dec.1a393", + "z": "246abd43.838a5a", "name": "", "property": "payload", "propertyType": "msg", @@ -2256,20 +1451,20 @@ "y": 200, "wires": [ [ - "7ce7cf66.df449" + "bd89c468.5a4f4" ], [ - "8846b607.310e9" + "762ab12c.cc7e88" ], [ - "5a8f4613.c9989" + "ecb1efe6.7cb968" ] ] }, { - "id": "7ce7cf66.df449", + "id": "bd89c468.5a4f4", "type": "change", - "z": "a8ad6dec.1a393", + "z": "246abd43.838a5a", "name": "The focus has started", "rules": [ { @@ -2289,14 +1484,14 @@ "y": 200, "wires": [ [ - "1597b08f.5bce8f" + "3b6b4fd4.8c3368" ] ] }, { - "id": "8846b607.310e9", + "id": "762ab12c.cc7e88", "type": "change", - "z": "a8ad6dec.1a393", + "z": "246abd43.838a5a", "name": "The focus has finished.", "rules": [ { @@ -2316,14 +1511,14 @@ "y": 240, "wires": [ [ - "1597b08f.5bce8f" + "3b6b4fd4.8c3368" ] ] }, { - "id": "5a8f4613.c9989", + "id": "ecb1efe6.7cb968", "type": "change", - "z": "a8ad6dec.1a393", + "z": "246abd43.838a5a", "name": "The focus has been stopped.", "rules": [ { @@ -2343,14 +1538,14 @@ "y": 280, "wires": [ [ - "1597b08f.5bce8f" + "3b6b4fd4.8c3368" ] ] }, { - "id": "d02a7968.b8874", + "id": "e43e94c.c297968", "type": "switch", - "z": "a8ad6dec.1a393", + "z": "246abd43.838a5a", "name": "", "property": "payload", "propertyType": "msg", @@ -2383,24 +1578,24 @@ "y": 360, "wires": [ [ - "d7f9086b.728df8" + "87a2aa4d.3590c8" ], [ - "c104db3.a287628" + "da9f9e9b.7c9f5" ], [ - "e99cb81d.b79df" + "1143b916.5047b7" ], [ - "3de45d76.06ab6a", - "1597b08f.5bce8f" + "fa7f2eaf.0e6f1", + "3b6b4fd4.8c3368" ] ] }, { - "id": "90e10524.6709f", + "id": "30c9c4c9.d46e3c", "type": "switch", - "z": "a8ad6dec.1a393", + "z": "246abd43.838a5a", "name": "", "property": "payload", "propertyType": "msg", @@ -2423,17 +1618,17 @@ "y": 560, "wires": [ [ - "6c8a5e5c.bf0f5" + "23e5c77c.4f63f" ], [ - "90433a26.6fc278" + "5491334a.93cbfc" ] ] }, { - "id": "c104db3.a287628", + "id": "da9f9e9b.7c9f5", "type": "change", - "z": "a8ad6dec.1a393", + "z": "246abd43.838a5a", "name": "The acquisition has finished.", "rules": [ { @@ -2453,14 +1648,14 @@ "y": 400, "wires": [ [ - "1597b08f.5bce8f" + "3b6b4fd4.8c3368" ] ] }, { - "id": "e99cb81d.b79df", + "id": "1143b916.5047b7", "type": "change", - "z": "a8ad6dec.1a393", + "z": "246abd43.838a5a", "name": "The acquisition has been stopped.", "rules": [ { @@ -2480,14 +1675,14 @@ "y": 440, "wires": [ [ - "1597b08f.5bce8f" + "3b6b4fd4.8c3368" ] ] }, { - "id": "d7f9086b.728df8", + "id": "87a2aa4d.3590c8", "type": "change", - "z": "a8ad6dec.1a393", + "z": "246abd43.838a5a", "name": "The acquisition has started", "rules": [ { @@ -2507,14 +1702,14 @@ "y": 360, "wires": [ [ - "1597b08f.5bce8f" + "3b6b4fd4.8c3368" ] ] }, { - "id": "3de45d76.06ab6a", + "id": "fa7f2eaf.0e6f1", "type": "function", - "z": "a8ad6dec.1a393", + "z": "246abd43.838a5a", "name": "img_counter.js", "func": "img_counter=global.get('img_counter')\nimg_counter=img_counter+1\nglobal.set('img_counter',img_counter)\nmsg.payload = img_counter\nreturn msg;", "outputs": 1, @@ -2523,14 +1718,14 @@ "y": 480, "wires": [ [ - "2f2c466d.88c6ba" + "582d7204.ec89fc" ] ] }, { - "id": "aebfa8a2.b4a928", + "id": "498b3d58.58b1a4", "type": "function", - "z": "a8ad6dec.1a393", + "z": "246abd43.838a5a", "name": "obj_counter.js", "func": "obj_counter=global.get('obj_counter')\nobj_counter=obj_counter+1\nglobal.set('obj_counter',obj_counter)\nmsg.payload = obj_counter\nreturn msg;", "outputs": 1, @@ -2539,14 +1734,14 @@ "y": 640, "wires": [ [ - "add1bf6d.b7a668" + "67618ae5.b74864" ] ] }, { - "id": "2f2c466d.88c6ba", + "id": "582d7204.ec89fc", "type": "ui_chart", - "z": "a8ad6dec.1a393", + "z": "246abd43.838a5a", "name": "img_counter", "group": "eb610eb9.84fae8", "order": 2, @@ -2586,9 +1781,9 @@ ] }, { - "id": "11e60fef.079d38", + "id": "b06c80f3.f1642", "type": "switch", - "z": "a8ad6dec.1a393", + "z": "246abd43.838a5a", "name": "", "property": "topic", "propertyType": "msg", @@ -2616,20 +1811,20 @@ "y": 560, "wires": [ [ - "90e10524.6709f" + "30c9c4c9.d46e3c" ], [ - "aebfa8a2.b4a928" + "498b3d58.58b1a4" ], [ - "7dd159b.6c105a8" + "33094026.f6e8c" ] ] }, { - "id": "90433a26.6fc278", + "id": "5491334a.93cbfc", "type": "change", - "z": "a8ad6dec.1a393", + "z": "246abd43.838a5a", "name": "The segmentation has finished.", "rules": [ { @@ -2649,14 +1844,14 @@ "y": 600, "wires": [ [ - "1597b08f.5bce8f" + "3b6b4fd4.8c3368" ] ] }, { - "id": "6c8a5e5c.bf0f5", + "id": "23e5c77c.4f63f", "type": "change", - "z": "a8ad6dec.1a393", + "z": "246abd43.838a5a", "name": "The segmentation has started", "rules": [ { @@ -2676,14 +1871,14 @@ "y": 560, "wires": [ [ - "1597b08f.5bce8f" + "3b6b4fd4.8c3368" ] ] }, { - "id": "add1bf6d.b7a668", + "id": "67618ae5.b74864", "type": "ui_chart", - "z": "a8ad6dec.1a393", + "z": "246abd43.838a5a", "name": "obj_counter", "group": "eb610eb9.84fae8", "order": 5, @@ -2723,9 +1918,9 @@ ] }, { - "id": "6f3399be.761c68", + "id": "3c29eb4.e570414", "type": "function", - "z": "a8ad6dec.1a393", + "z": "246abd43.838a5a", "name": "", "func": "msg.payload=msg.payload.object_area\nmsg.topic=\"area\"\n\nreturn msg;", "outputs": 1, @@ -2734,14 +1929,14 @@ "y": 700, "wires": [ [ - "e50c9bb6.397a08" + "84dfe51a.0e9fd" ] ] }, { - "id": "7dd159b.6c105a8", + "id": "33094026.f6e8c", "type": "json", - "z": "a8ad6dec.1a393", + "z": "246abd43.838a5a", "name": "", "property": "payload", "action": "", @@ -2750,14 +1945,14 @@ "y": 700, "wires": [ [ - "6f3399be.761c68" + "3c29eb4.e570414" ] ] }, { - "id": "b56d820b.9f7b", + "id": "9b672325.568a18", "type": "exec", - "z": "a8ad6dec.1a393", + "z": "246abd43.838a5a", "command": "free -m | grep \"Mem\" | awk -F ' ' '{print $3}'", "addpay": false, "append": "", @@ -2768,16 +1963,16 @@ "y": 780, "wires": [ [ - "bb46922a.0aa378" + "76a7ddb6.fbde64" ], [], [] ] }, { - "id": "7c27a4b2.6fe8e4", + "id": "7c9eaef6.142a4", "type": "inject", - "z": "a8ad6dec.1a393", + "z": "246abd43.838a5a", "name": "", "topic": "", "payload": "", @@ -2790,14 +1985,14 @@ "y": 780, "wires": [ [ - "b56d820b.9f7b" + "9b672325.568a18" ] ] }, { - "id": "bb46922a.0aa378", + "id": "76a7ddb6.fbde64", "type": "ui_chart", - "z": "a8ad6dec.1a393", + "z": "246abd43.838a5a", "name": "", "group": "eb610eb9.84fae8", "order": 1, @@ -2837,9 +2032,9 @@ ] }, { - "id": "e50c9bb6.397a08", + "id": "84dfe51a.0e9fd", "type": "ui_chart", - "z": "a8ad6dec.1a393", + "z": "246abd43.838a5a", "name": "", "group": "eb610eb9.84fae8", "order": 8, @@ -2879,9 +2074,9 @@ ] }, { - "id": "1597b08f.5bce8f", + "id": "3b6b4fd4.8c3368", "type": "ui_toast", - "z": "a8ad6dec.1a393", + "z": "246abd43.838a5a", "position": "top right", "displayTime": "3", "highlight": "", @@ -2897,62 +2092,69 @@ "wires": [] }, { - "id": "85ced3a9.8bc898", - "type": "exec", - "z": "9882c53a.0ccc8", - "command": "vcgencmd measure_temp | tr -d \"temp=\" | tr -d \"'C\" | tr -d \"\\n\"", - "addpay": false, - "append": "", - "useSpawn": "", - "timer": "", - "name": "RPi Temp.", - "x": 350, - "y": 80, - "wires": [ - [ - "8715b9fb.194438" - ], - [], - [] - ] - }, - { - "id": "3bb0ef9d.258af8", - "type": "inject", - "z": "9882c53a.0ccc8", + "id": "613bee5b.042fe", + "type": "debug", + "z": "246abd43.838a5a", "name": "", - "topic": "", - "payload": "", - "payloadType": "date", - "repeat": "10", - "crontab": "", - "once": false, - "onceDelay": "", - "x": 190, - "y": 80, - "wires": [ - [ - "85ced3a9.8bc898" - ] - ] + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "x": 240, + "y": 140, + "wires": [] }, { - "id": "8715b9fb.194438", - "type": "python3-function", - "z": "9882c53a.0ccc8", - "name": "fan.py", - "func": "#!/usr/bin/python\nimport smbus\nimport sys\n\ntemp = msg[\"payload\"]\n\ntemp = int(temp.split('.',1)[0])\n\nbus = smbus.SMBus(1)\n\nDEVICE_ADDRESS = 0x0d\n\nif temp < 38:\n bus.write_byte_data(DEVICE_ADDRESS, 0x08, 0x00)\n bus.write_byte_data(DEVICE_ADDRESS, 0x08, 0x00)\nif temp > 42:\n bus.write_byte_data(DEVICE_ADDRESS, 0x08, 0x01)\n bus.write_byte_data(DEVICE_ADDRESS, 0x08, 0x01)", - "outputs": 1, - "x": 530, - "y": 80, - "wires": [ - [] - ] + "id": "84801dc0.193d88", + "type": "mqtt-broker", + "z": "", + "name": "", + "broker": "127.0.0.1", + "port": "1883", + "clientid": "test", + "usetls": false, + "compatmode": false, + "keepalive": "60", + "cleansession": true, + "birthTopic": "", + "birthQos": "0", + "birthPayload": "", + "closeTopic": "", + "closeQos": "0", + "closePayload": "", + "willTopic": "", + "willQos": "0", + "willPayload": "" }, { - "id": "7bdf69d9.8f98e", + "id": "eb610eb9.84fae8", + "type": "ui_group", + "z": "", + "name": "MQTT Plots", + "tab": "2b97fe34.a699fa", + "order": 11, + "disp": true, + "width": "24", + "collapse": false + }, + { + "id": "1273b673.4a35ea", + "type": "subflow", + "name": "System Commands", + "info": "", + "category": "", + "in": [], + "out": [], + "env": [], + "color": "#FFCC66", + "icon": "node-red-dashboard/ui_button.png" + }, + { + "id": "44a78834.e8f8b8", "type": "ui_button", - "z": "fbe9590f.bd63b8", + "z": "1273b673.4a35ea", "name": "", "group": "82b3caaa.0518", "order": 1, @@ -2971,14 +2173,14 @@ "y": 80, "wires": [ [ - "c55ff479.c166a8" + "aba9aac1.c2d198" ] ] }, { - "id": "f400fb5a.9bc108", + "id": "a32bfa65.bc6b9", "type": "exec", - "z": "fbe9590f.bd63b8", + "z": "1273b673.4a35ea", "command": "sudo", "addpay": true, "append": "", @@ -2995,9 +2197,9 @@ ] }, { - "id": "867e9bed.e2a298", + "id": "825c8791.c0bfb", "type": "ui_button", - "z": "fbe9590f.bd63b8", + "z": "1273b673.4a35ea", "name": "", "group": "82b3caaa.0518", "order": 2, @@ -3016,14 +2218,14 @@ "y": 140, "wires": [ [ - "c55ff479.c166a8" + "aba9aac1.c2d198" ] ] }, { - "id": "c55ff479.c166a8", + "id": "aba9aac1.c2d198", "type": "python3-function", - "z": "fbe9590f.bd63b8", + "z": "1273b673.4a35ea", "name": "action", "func": "#!/usr/bin/python\nimport smbus\nimport time\nbus = smbus.SMBus(1)\ntime.sleep(1)\n#turn off fan RGB\nbus.write_byte_data(0x0d, 0x07, 0x00)\nbus.write_byte_data(0x0d, 0x07, 0x00)\n\nmsg[\"payload\"] = str(msg[\"topic\"])+' now'\nreturn msg", "outputs": 1, @@ -3031,15 +2233,15 @@ "y": 100, "wires": [ [ - "46f85d17.08fa54", - "f400fb5a.9bc108" + "72b7368a.abad3", + "a32bfa65.bc6b9" ] ] }, { - "id": "46f85d17.08fa54", + "id": "72b7368a.abad3", "type": "exec", - "z": "fbe9590f.bd63b8", + "z": "1273b673.4a35ea", "command": "i2cdetect -y 1", "addpay": false, "append": "", @@ -3056,9 +2258,76 @@ ] }, { - "id": "cf0b247b.e3e7c", + "id": "82b3caaa.0518", + "type": "ui_group", + "z": "", + "name": "Commands", + "tab": "2b97fe34.a699fa", + "order": 12, + "disp": true, + "width": 24, + "collapse": false + }, + { + "id": "506e9090.6e905", + "type": "subflow", + "name": "Object metadata", + "info": "", + "category": "", + "in": [ + { + "x": 40, + "y": 40, + "wires": [ + { + "id": "4ab4976c.eee488" + }, + { + "id": "581c8a23.83fa8c" + }, + { + "id": "52052007.b3d0e" + } + ] + } + ], + "out": [ + { + "x": 1060, + "y": 159, + "wires": [ + { + "id": "26b33a5c.0ef82e", + "port": 0 + }, + { + "id": "9ee0935a.415808", + "port": 0 + } + ] + }, + { + "x": 1060, + "y": 59, + "wires": [ + { + "id": "d3875217.e3b668", + "port": 0 + }, + { + "id": "82fef572.49b5f", + "port": 0 + } + ] + } + ], + "env": [], + "color": "#DDAA99" + }, + { + "id": "26b33a5c.0ef82e", "type": "ui_numeric", - "z": "b45c6fb6.f6dfa8", + "z": "506e9090.6e905", "name": "object_depth_min", "label": "Minimum depth (m)", "tooltip": "", @@ -3080,9 +2349,9 @@ ] }, { - "id": "1675637a.1d762d", + "id": "9ee0935a.415808", "type": "ui_numeric", - "z": "b45c6fb6.f6dfa8", + "z": "506e9090.6e905", "name": "object_depth_max", "label": "Maximum depth (m)", "tooltip": "", @@ -3104,9 +2373,9 @@ ] }, { - "id": "8a61177.8eaa1e8", + "id": "4ab4976c.eee488", "type": "function", - "z": "b45c6fb6.f6dfa8", + "z": "506e9090.6e905", "name": "get object_depth_min", "func": "msg.payload = msg.payload.object_depth_min;\nreturn msg;", "outputs": 1, @@ -3115,14 +2384,14 @@ "y": 120, "wires": [ [ - "cf0b247b.e3e7c" + "26b33a5c.0ef82e" ] ] }, { - "id": "3893c81e.a9b9e", + "id": "581c8a23.83fa8c", "type": "function", - "z": "b45c6fb6.f6dfa8", + "z": "506e9090.6e905", "name": "get object_depth_max", "func": "msg.payload = msg.payload.object_depth_max;\nreturn msg;", "outputs": 1, @@ -3131,14 +2400,14 @@ "y": 160, "wires": [ [ - "1675637a.1d762d" + "9ee0935a.415808" ] ] }, { - "id": "f478b054.024158", + "id": "472998cd.45f588", "type": "gpsd", - "z": "b45c6fb6.f6dfa8", + "z": "506e9090.6e905", "name": "", "hostname": "localhost", "port": "2947", @@ -3152,15 +2421,15 @@ "y": 220, "wires": [ [ - "bd643763.2a7768", - "edee5fda.673ae" + "52052007.b3d0e", + "ab40705d.43a5d" ] ] }, { - "id": "ca169437.bb25e8", + "id": "7d5701.1e1981", "type": "ui_worldmap", - "z": "b45c6fb6.f6dfa8", + "z": "506e9090.6e905", "d": true, "group": "f377d75b.32d27", "order": 1, @@ -3187,9 +2456,9 @@ "wires": [] }, { - "id": "bd643763.2a7768", + "id": "52052007.b3d0e", "type": "function", - "z": "b45c6fb6.f6dfa8", + "z": "506e9090.6e905", "name": "get object_lat & object_lon", "func": "\nreturn msg;", "outputs": 1, @@ -3198,14 +2467,14 @@ "y": 200, "wires": [ [ - "ca169437.bb25e8" + "7d5701.1e1981" ] ] }, { - "id": "d485fec3.802e", + "id": "d3875217.e3b668", "type": "function", - "z": "b45c6fb6.f6dfa8", + "z": "506e9090.6e905", "name": "set object_time", "func": "var time = new Date(msg.payload);\n\nvar hour = time.getUTCHours();\nif (hour<10){hour = \"0\"+hour;}\nvar minute = time.getUTCMinutes();\nif (minute<10){minute = \"0\"+minute;}\n\nvar time_UTC = \"\"+hour+minute;\nglobal.set('object_time',time_UTC);\nreturn msg;", "outputs": 1, @@ -3217,9 +2486,9 @@ ] }, { - "id": "5196107b.a5eae8", + "id": "82fef572.49b5f", "type": "function", - "z": "b45c6fb6.f6dfa8", + "z": "506e9090.6e905", "name": "set object_date", "func": "var date = new Date(msg.payload);\n\nvar year = date.getUTCFullYear();\nvar month = date.getUTCMonth()+1;\nif (month<10){month = \"0\"+month;}\nvar day = date.getUTCDate();\nif (day<10){day = \"0\"+day;}\n\nvar date_UTC = \"\"+year+month+day;\nglobal.set('object_date',date_UTC);\n\nreturn msg;", "outputs": 1, @@ -3231,9 +2500,9 @@ ] }, { - "id": "edee5fda.673ae", + "id": "ab40705d.43a5d", "type": "debug", - "z": "b45c6fb6.f6dfa8", + "z": "506e9090.6e905", "name": "", "active": true, "tosidebar": true, @@ -3246,9 +2515,114 @@ "wires": [] }, { - "id": "5a5fcc9a.9ede14", + "id": "f377d75b.32d27", + "type": "ui_group", + "z": "", + "name": "Object metadata", + "tab": "2b97fe34.a699fa", + "order": 6, + "disp": true, + "width": "24", + "collapse": false + }, + { + "id": "97d77aeb.75afd8", + "type": "subflow", + "name": "Acquisition metadata", + "info": "", + "category": "", + "in": [ + { + "x": 50, + "y": 30, + "wires": [ + { + "id": "282cae65.749e9a" + }, + { + "id": "cc899daf.a8d5d8" + }, + { + "id": "9873f1c8.6cb608" + }, + { + "id": "e53df171.eed68" + }, + { + "id": "5f728563.cf6214" + }, + { + "id": "c1a5eaf5.8691c" + }, + { + "id": "86c63d98.eb21" + }, + { + "id": "3707a612.b8619a" + }, + { + "id": "b2d20d5d.fd9e38" + } + ] + } + ], + "out": [ + { + "x": 740, + "y": 40, + "wires": [ + { + "id": "3b267291.1eee26", + "port": 0 + }, + { + "id": "435a2dcf.a1a60c", + "port": 0 + }, + { + "id": "cc6cb58d.b2dbe8", + "port": 0 + }, + { + "id": "8b306bbc.914", + "port": 0 + }, + { + "id": "2a5a2b7a.f218d4", + "port": 0 + }, + { + "id": "28df07d8.d71ba8", + "port": 0 + }, + { + "id": "6cf2c1ac.a0fea8", + "port": 0 + }, + { + "id": "e7c4132f.f4417", + "port": 0 + } + ] + }, + { + "x": 900, + "y": 360, + "wires": [ + { + "id": "1e688c91.1b805b", + "port": 0 + } + ] + } + ], + "env": [], + "color": "#DDAA99" + }, + { + "id": "1e688c91.1b805b", "type": "function", - "z": "6ca1a253.126bb4", + "z": "97d77aeb.75afd8", "name": "set optical config", "func": "global.set(msg.topic,msg.payload);\nvar acq_fnumber_objective = String(global.get(msg.topic));\n\nswitch(acq_fnumber_objective) {\n case \"25\":\n global.set(\"acq_magnification\",0.6);\n global.set(\"process_pixel\",1.86);\n global.set(\"sug_min\",60);\n global.set(\"sug_max\",670);\n global.set(\"sug_flowrate\",3);\n break;\n case \"16\":\n global.set(\"acq_magnification\",0.94);\n global.set(\"process_pixel\",1.19);\n global.set(\"sug_min\",40);\n global.set(\"sug_max\",430);\n global.set(\"sug_flowrate\",2.4);\n break;\n case \"12\":\n global.set(\"acq_magnification\",1.20);\n global.set(\"process_pixel\",0.94);\n global.set(\"sug_min\",30);\n global.set(\"sug_max\",340);\n global.set(\"sug_flowrate\",1.25);\n break;\n case \"8\":\n global.set(\"acq_magnification\",1.78);\n global.set(\"process_pixel\",0.63);\n global.set(\"sug_min\",20);\n global.set(\"sug_max\",230);\n global.set(\"sug_flowrate\",0.42);\n break;\n case \"6\":\n global.set(\"acq_magnification\",2.36);\n global.set(\"process_pixel\",0.48);\n global.set(\"sug_min\",15);\n global.set(\"sug_max\",170);\n global.set(\"sug_flowrate\",0.32);\n break;\n}\nreturn msg;", "outputs": 1, @@ -3260,9 +2634,9 @@ ] }, { - "id": "3d3aafbf.e907a8", + "id": "2877f2f.211cc8e", "type": "ui_dropdown", - "z": "6ca1a253.126bb4", + "z": "97d77aeb.75afd8", "name": "acq_fnumber_objective", "label": "M12 Lens*", "tooltip": "", @@ -3305,14 +2679,14 @@ "y": 360, "wires": [ [ - "5a5fcc9a.9ede14" + "1e688c91.1b805b" ] ] }, { - "id": "12e818fa.b7301f", + "id": "8b306bbc.914", "type": "ui_numeric", - "z": "6ca1a253.126bb4", + "z": "97d77aeb.75afd8", "name": "acq_minimum_mesh", "label": "Min fraction size (μm)", "tooltip": "", @@ -3334,9 +2708,9 @@ ] }, { - "id": "b577dcd2.8d2c88", + "id": "2a5a2b7a.f218d4", "type": "ui_numeric", - "z": "6ca1a253.126bb4", + "z": "97d77aeb.75afd8", "name": "acq_maximum_mesh", "label": "Max fraction size (μm)", "tooltip": "", @@ -3358,9 +2732,9 @@ ] }, { - "id": "21b35429.fe43a4", + "id": "3b267291.1eee26", "type": "ui_text_input", - "z": "6ca1a253.126bb4", + "z": "97d77aeb.75afd8", "name": "acq_id", "label": "Acquisition unique ID*", "tooltip": "", @@ -3379,9 +2753,9 @@ ] }, { - "id": "c4e69883.a0f3d", + "id": "cc6cb58d.b2dbe8", "type": "ui_dropdown", - "z": "6ca1a253.126bb4", + "z": "97d77aeb.75afd8", "name": "acq_celltype", "label": "Thickness flowcell*", "tooltip": "", @@ -3422,9 +2796,9 @@ ] }, { - "id": "f7f5ccc1.29a41", + "id": "28df07d8.d71ba8", "type": "ui_text_input", - "z": "6ca1a253.126bb4", + "z": "97d77aeb.75afd8", "name": "acq_volume", "label": "Volume to pass (ml)", "tooltip": "", @@ -3443,9 +2817,9 @@ ] }, { - "id": "f0595ff1.c4d568", + "id": "435a2dcf.a1a60c", "type": "ui_text_input", - "z": "6ca1a253.126bb4", + "z": "97d77aeb.75afd8", "name": "acq_instrument", "label": "Acquisition instrument", "tooltip": "PlanktonScope V2.1", @@ -3464,9 +2838,9 @@ ] }, { - "id": "93a3fd29.c55938", + "id": "282cae65.749e9a", "type": "function", - "z": "6ca1a253.126bb4", + "z": "97d77aeb.75afd8", "name": "get acq_id", "func": "msg.payload = msg.payload.acq_id+1;\nreturn msg;", "outputs": 1, @@ -3475,14 +2849,14 @@ "y": 40, "wires": [ [ - "21b35429.fe43a4" + "3b267291.1eee26" ] ] }, { - "id": "9e9e7f8a.b66d4", + "id": "cc899daf.a8d5d8", "type": "function", - "z": "6ca1a253.126bb4", + "z": "97d77aeb.75afd8", "name": "get acq_instrument", "func": "msg.payload = msg.payload.acq_instrument;\nreturn msg;", "outputs": 1, @@ -3491,14 +2865,14 @@ "y": 80, "wires": [ [ - "f0595ff1.c4d568" + "435a2dcf.a1a60c" ] ] }, { - "id": "b1105180.b4b78", + "id": "9873f1c8.6cb608", "type": "function", - "z": "6ca1a253.126bb4", + "z": "97d77aeb.75afd8", "name": "get acq_celltype", "func": "msg.payload = msg.payload.acq_celltype;\nreturn msg;", "outputs": 1, @@ -3507,14 +2881,14 @@ "y": 120, "wires": [ [ - "c4e69883.a0f3d" + "cc6cb58d.b2dbe8" ] ] }, { - "id": "ec403304.e34c58", + "id": "e53df171.eed68", "type": "function", - "z": "6ca1a253.126bb4", + "z": "97d77aeb.75afd8", "name": "get acq_minimum_mesh", "func": "msg.payload = msg.payload.acq_minimum_mesh;\nreturn msg;", "outputs": 1, @@ -3523,14 +2897,14 @@ "y": 160, "wires": [ [ - "12e818fa.b7301f" + "8b306bbc.914" ] ] }, { - "id": "7aac5c46.0669ec", + "id": "5f728563.cf6214", "type": "function", - "z": "6ca1a253.126bb4", + "z": "97d77aeb.75afd8", "name": "get acq_maximum_mesh", "func": "msg.payload = msg.payload.acq_maximum_mesh;\nreturn msg;", "outputs": 1, @@ -3539,14 +2913,14 @@ "y": 200, "wires": [ [ - "b577dcd2.8d2c88" + "2a5a2b7a.f218d4" ] ] }, { - "id": "c491cf7.36957b", + "id": "c1a5eaf5.8691c", "type": "function", - "z": "6ca1a253.126bb4", + "z": "97d77aeb.75afd8", "name": "get acq_volume", "func": "msg.payload = msg.payload.acq_volume;\nreturn msg;", "outputs": 1, @@ -3555,14 +2929,14 @@ "y": 240, "wires": [ [ - "f7f5ccc1.29a41" + "28df07d8.d71ba8" ] ] }, { - "id": "31d58fcd.ede758", + "id": "b2d20d5d.fd9e38", "type": "function", - "z": "6ca1a253.126bb4", + "z": "97d77aeb.75afd8", "name": "get acq_fnumber_objective", "func": "msg.payload = msg.payload.acq_fnumber_objective;\nreturn msg;", "outputs": 1, @@ -3571,14 +2945,14 @@ "y": 360, "wires": [ [ - "3d3aafbf.e907a8" + "2877f2f.211cc8e" ] ] }, { - "id": "bd733bef.7efd08", + "id": "6cf2c1ac.a0fea8", "type": "ui_numeric", - "z": "6ca1a253.126bb4", + "z": "97d77aeb.75afd8", "name": "acq_min_esd", "label": "Minimum size to segment (μm)", "tooltip": "", @@ -3600,9 +2974,9 @@ ] }, { - "id": "a6057924.bc14", + "id": "e7c4132f.f4417", "type": "ui_numeric", - "z": "6ca1a253.126bb4", + "z": "97d77aeb.75afd8", "name": "acq_max_esd", "label": "Maximum size to segment (μm)", "tooltip": "", @@ -3624,9 +2998,9 @@ ] }, { - "id": "e0644195.305068", + "id": "86c63d98.eb21", "type": "function", - "z": "6ca1a253.126bb4", + "z": "97d77aeb.75afd8", "name": "get acq_min_esd", "func": "msg.payload = msg.payload.acq_min_esd;\nreturn msg;", "outputs": 1, @@ -3635,14 +3009,14 @@ "y": 280, "wires": [ [ - "bd733bef.7efd08" + "6cf2c1ac.a0fea8" ] ] }, { - "id": "e3fe6242.bfaf18", + "id": "3707a612.b8619a", "type": "function", - "z": "6ca1a253.126bb4", + "z": "97d77aeb.75afd8", "name": "get acq_max_esd", "func": "msg.payload = msg.payload.acq_max_esd;\nreturn msg;", "outputs": 1, @@ -3651,14 +3025,65 @@ "y": 320, "wires": [ [ - "a6057924.bc14" + "e7c4132f.f4417" ] ] }, { - "id": "edfb5b10.95636", + "id": "60b93a5.a032344", + "type": "ui_group", + "z": "", + "name": "Acquisition metadata", + "tab": "2b97fe34.a699fa", + "order": 7, + "disp": true, + "width": "24", + "collapse": false + }, + { + "id": "9a45991b.365bc8", + "type": "subflow", + "name": "Pump actuation", + "info": "", + "category": "", + "in": [ + { + "x": 40, + "y": 40, + "wires": [ + { + "id": "eb7c01ae.d00358" + }, + { + "id": "642ae1f3.cf7d28" + } + ] + } + ], + "out": [ + { + "x": 700, + "y": 40, + "wires": [ + { + "id": "4485759b.52ee74", + "port": 0 + }, + { + "id": "3283f063.31c548", + "port": 0 + } + ] + } + ], + "env": [], + "color": "#A6BBCF", + "icon": "font-awesome/fa-recycle" + }, + { + "id": "6246d9ef.156bd", "type": "function", - "z": "626459d2.f9c98", + "z": "9a45991b.365bc8", "name": "pump.js", "func": "state = global.get(\"state\");\n\nif (state == null){state=\"free\"}\n\nvar 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 \n}else if (flowrate === undefined || flowrate === \"\" || flowrate === null) {\n msg.topic = \"Missing entry :\"\n msg.payload = \"Flowrate\";\n \n}else {\n volume = global.get(\"pump_manual_volume\");\n nb_step=volume*507\n msg.volume = volume;\n flowrate = global.get(\"pump_flowrate\");\n duration=(volume*60)/flowrate\n delay=(duration/nb_step)-0.005\n msg.topic = \"actuator/pump\";\n \n if(msg.payload === \"FORWARD\" & state===\"free\"){\n msg.payload='FORWARD '+delay+' '+nb_step;\n }\n if(msg.payload === \"BACKWARD\" & state===\"free\"){\n msg.payload='BACKWARD '+delay+' '+nb_step;\n }\n}\nreturn msg;", "outputs": 1, @@ -3667,15 +3092,15 @@ "y": 140, "wires": [ [ - "fb35e49.f64de18" + "53bef09a.8102e" ] ], "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/PlanktonScope/scripts/focus.py 650 up\n" }, { - "id": "26686514.749b4a", + "id": "2374d55d.a3e3a2", "type": "ui_button", - "z": "626459d2.f9c98", + "z": "9a45991b.365bc8", "name": "BACKWARD", "group": "4153382f.45437", "order": 2, @@ -3694,14 +3119,14 @@ "y": 120, "wires": [ [ - "edfb5b10.95636" + "6246d9ef.156bd" ] ] }, { - "id": "bee2fd6d.cffb28", + "id": "c8aa9753.f51c08", "type": "ui_button", - "z": "626459d2.f9c98", + "z": "9a45991b.365bc8", "name": "FORWARD", "group": "4153382f.45437", "order": 4, @@ -3720,14 +3145,14 @@ "y": 160, "wires": [ [ - "edfb5b10.95636" + "6246d9ef.156bd" ] ] }, { - "id": "fb35e49.f64de18", + "id": "53bef09a.8102e", "type": "switch", - "z": "626459d2.f9c98", + "z": "9a45991b.365bc8", "name": "", "property": "topic", "propertyType": "msg", @@ -3750,17 +3175,17 @@ "y": 140, "wires": [ [ - "f6aa3e03.85018" + "4d3bf3c2.6a380c" ], [ - "f6dcda51.633398" + "d943e58a.e85fc" ] ] }, { - "id": "f6dcda51.633398", + "id": "d943e58a.e85fc", "type": "ui_toast", - "z": "626459d2.f9c98", + "z": "9a45991b.365bc8", "position": "dialog", "displayTime": "3", "highlight": "", @@ -3778,9 +3203,9 @@ ] }, { - "id": "c3edd9e7.1ac36", + "id": "eaa22490.6843d", "type": "ui_button", - "z": "626459d2.f9c98", + "z": "9a45991b.365bc8", "name": "stop pump", "group": "4153382f.45437", "order": 5, @@ -3799,14 +3224,14 @@ "y": 200, "wires": [ [ - "2521ba15.88a58e" + "9e71b7a5.28dff8" ] ] }, { - "id": "f6aa3e03.85018", + "id": "4d3bf3c2.6a380c", "type": "mqtt out", - "z": "626459d2.f9c98", + "z": "9a45991b.365bc8", "name": "", "topic": "", "qos": "", @@ -3817,9 +3242,9 @@ "wires": [] }, { - "id": "2521ba15.88a58e", + "id": "9e71b7a5.28dff8", "type": "mqtt out", - "z": "626459d2.f9c98", + "z": "9a45991b.365bc8", "name": "", "topic": "", "qos": "", @@ -3830,9 +3255,9 @@ "wires": [] }, { - "id": "2f9ec1a6.d5fb66", + "id": "3283f063.31c548", "type": "ui_text_input", - "z": "626459d2.f9c98", + "z": "9a45991b.365bc8", "name": "pump_manual_volume", "label": "Volume to pass (ml)", "tooltip": "", @@ -3851,9 +3276,9 @@ ] }, { - "id": "50093f5.8e35ec", + "id": "642ae1f3.cf7d28", "type": "function", - "z": "626459d2.f9c98", + "z": "9a45991b.365bc8", "name": "get pump_manual_volume", "func": "msg.payload = msg.payload.pump_manual_volume;\nreturn msg;", "outputs": 1, @@ -3862,14 +3287,14 @@ "y": 80, "wires": [ [ - "2f9ec1a6.d5fb66" + "3283f063.31c548" ] ] }, { - "id": "fa485315.928ae", + "id": "4485759b.52ee74", "type": "ui_slider", - "z": "626459d2.f9c98", + "z": "9a45991b.365bc8", "name": "pump_flowrate", "label": "Flowrate (ml/min)*", "tooltip": "", @@ -3890,9 +3315,9 @@ ] }, { - "id": "f7b6f5e7.7b7ca", + "id": "eb7c01ae.d00358", "type": "function", - "z": "626459d2.f9c98", + "z": "9a45991b.365bc8", "name": "get pump_flowrate", "func": "msg.payload = msg.payload.pump_flowrate;\nreturn msg;", "outputs": 1, @@ -3901,14 +3326,58 @@ "y": 40, "wires": [ [ - "fa485315.928ae" + "4485759b.52ee74" ] ] }, { - "id": "7297e2f7.dce564", + "id": "4153382f.45437", + "type": "ui_group", + "z": "", + "name": "Pump actuation", + "tab": "2b97fe34.a699fa", + "order": 5, + "disp": true, + "width": "24", + "collapse": false + }, + { + "id": "ac806d39.1682a8", + "type": "subflow", + "name": "Focus actuation", + "info": "", + "category": "", + "in": [ + { + "x": 40, + "y": 40, + "wires": [ + { + "id": "c631467a.569ba" + } + ] + } + ], + "out": [ + { + "x": 800, + "y": 200, + "wires": [ + { + "id": "97bf666e.4d3ad", + "port": 0 + } + ] + } + ], + "env": [], + "color": "#A6BBCF", + "icon": "node-red/sort.svg" + }, + { + "id": "97bf666e.4d3ad", "type": "ui_text_input", - "z": "5c516299.73e054", + "z": "ac806d39.1682a8", "name": "focus_nb_step", "label": "Number of step(s)", "tooltip": "", @@ -3927,9 +3396,9 @@ ] }, { - "id": "60dc5851.6962b", + "id": "c631467a.569ba", "type": "function", - "z": "5c516299.73e054", + "z": "ac806d39.1682a8", "name": "get focus_nb_step", "func": "msg.payload = msg.payload.focus_nb_step;\nreturn msg;", "outputs": 1, @@ -3938,14 +3407,14 @@ "y": 40, "wires": [ [ - "7297e2f7.dce564" + "97bf666e.4d3ad" ] ] }, { - "id": "7200408d.a1be4", + "id": "8346f4af.5c0978", "type": "ui_button", - "z": "5c516299.73e054", + "z": "ac806d39.1682a8", "name": "DOWN", "group": "69433259.f306fc", "order": 3, @@ -3964,14 +3433,14 @@ "y": 120, "wires": [ [ - "2e2a455b.5ff4fa" + "350c388d.12cd28" ] ] }, { - "id": "7f823e6.d3bcfc", + "id": "7ee30e1c.691bd", "type": "ui_button", - "z": "5c516299.73e054", + "z": "ac806d39.1682a8", "name": "UP", "group": "69433259.f306fc", "order": 1, @@ -3990,14 +3459,14 @@ "y": 81, "wires": [ [ - "2e2a455b.5ff4fa" + "350c388d.12cd28" ] ] }, { - "id": "54482c7a.a384ac", + "id": "a2f04fac.5a338", "type": "switch", - "z": "5c516299.73e054", + "z": "ac806d39.1682a8", "name": "", "property": "topic", "propertyType": "msg", @@ -4020,17 +3489,17 @@ "y": 100, "wires": [ [ - "2a7a3d34.08e2a2" + "9fd904e.d1cbcf8" ], [ - "4277442b.04d1b4" + "ccd4fa1e.152" ] ] }, { - "id": "4277442b.04d1b4", + "id": "ccd4fa1e.152", "type": "ui_toast", - "z": "5c516299.73e054", + "z": "ac806d39.1682a8", "position": "dialog", "displayTime": "3", "highlight": "", @@ -4048,9 +3517,9 @@ ] }, { - "id": "2e2a455b.5ff4fa", + "id": "350c388d.12cd28", "type": "function", - "z": "5c516299.73e054", + "z": "ac806d39.1682a8", "name": "focus.js", "func": "state = global.get(\"state\");\n\nif (state == null){state=\"free\"}\n\nvar nb_step= global.get(\"focus_nb_step\");\n\nif (nb_step === undefined || nb_step === \"\" || nb_step === null) {\n msg.topic = \"Missing entry :\"\n msg.payload = \"Number of steps\";\n \n}else {\n nb_step= global.get(\"focus_nb_step\");\n if(msg.payload === \"UP\" & state===\"free\"){\n msg.payload=\"FORWARD \"+nb_step;\n }\n if(msg.payload === \"DOWN\" & state===\"free\"){\n msg.payload=\"BACKWARD \"+nb_step;\n }\n}\nreturn msg;", "outputs": 1, @@ -4059,15 +3528,15 @@ "y": 100, "wires": [ [ - "54482c7a.a384ac" + "a2f04fac.5a338" ] ], "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/PlanktonScope/scripts/focus.py 650 up\n" }, { - "id": "73e0d0c.c07ab3", + "id": "da904b2b.4a1d68", "type": "ui_button", - "z": "5c516299.73e054", + "z": "ac806d39.1682a8", "name": "stop focus", "group": "69433259.f306fc", "order": 4, @@ -4086,14 +3555,14 @@ "y": 160, "wires": [ [ - "8e86348d.69657" + "8bb9c09d.bc8178" ] ] }, { - "id": "2a7a3d34.08e2a2", + "id": "9fd904e.d1cbcf8", "type": "mqtt out", - "z": "5c516299.73e054", + "z": "ac806d39.1682a8", "name": "", "topic": "", "qos": "", @@ -4104,9 +3573,9 @@ "wires": [] }, { - "id": "8e86348d.69657", + "id": "8bb9c09d.bc8178", "type": "mqtt out", - "z": "5c516299.73e054", + "z": "ac806d39.1682a8", "name": "", "topic": "", "qos": "", @@ -4117,9 +3586,102 @@ "wires": [] }, { - "id": "10f1e5c1.3cb69a", + "id": "69433259.f306fc", + "type": "ui_group", + "z": "", + "name": "Focus actuation", + "tab": "2b97fe34.a699fa", + "order": 4, + "disp": true, + "width": "24", + "collapse": false + }, + { + "id": "e8ab36cc.74d77", + "type": "mqtt-broker", + "z": "", + "name": "", + "broker": "0.0.0.0", + "port": "1883", + "clientid": "Client_node", + "usetls": false, + "compatmode": false, + "keepalive": "60", + "cleansession": true, + "birthTopic": "", + "birthQos": "0", + "birthPayload": "", + "closeTopic": "", + "closeQos": "0", + "closePayload": "", + "willTopic": "", + "willQos": "0", + "willPayload": "" + }, + { + "id": "5c6dd7ee.546fa8", + "type": "subflow", + "name": "Sample metadata", + "info": "", + "category": "", + "in": [ + { + "x": 40, + "y": 40, + "wires": [ + { + "id": "730e3aa0.75f6dc" + }, + { + "id": "b49441ee.07b358" + }, + { + "id": "77454044.f47e88" + }, + { + "id": "203e3416.6c480c" + }, + { + "id": "3555467a.6ba1ea" + } + ] + } + ], + "out": [ + { + "x": 840, + "y": 40, + "wires": [ + { + "id": "419967b7.b9b5f", + "port": 0 + }, + { + "id": "9b3f7b46.107718", + "port": 0 + }, + { + "id": "6f24740b.fbae5c", + "port": 0 + }, + { + "id": "bf7a47c8.a960b8", + "port": 0 + }, + { + "id": "327afe96.262122", + "port": 0 + } + ] + } + ], + "env": [], + "color": "#DDAA99" + }, + { + "id": "6f24740b.fbae5c", "type": "ui_text_input", - "z": "efeebffd.34c7e", + "z": "5c6dd7ee.546fa8", "name": "sample_ship", "label": "Name of the ship", "tooltip": "", @@ -4138,9 +3700,9 @@ ] }, { - "id": "da0c5a96.74c0e", + "id": "327afe96.262122", "type": "ui_dropdown", - "z": "efeebffd.34c7e", + "z": "5c6dd7ee.546fa8", "name": "sample_sampling_gear", "label": "Sampling gear", "tooltip": "", @@ -4186,9 +3748,9 @@ ] }, { - "id": "aa90b06d.ca78e", + "id": "bf7a47c8.a960b8", "type": "ui_text_input", - "z": "efeebffd.34c7e", + "z": "5c6dd7ee.546fa8", "name": "sample_operator", "label": "Name of the operator", "tooltip": "", @@ -4207,9 +3769,9 @@ ] }, { - "id": "1cb896c7.6dfc11", + "id": "419967b7.b9b5f", "type": "ui_text_input", - "z": "efeebffd.34c7e", + "z": "5c6dd7ee.546fa8", "name": "sample_project", "label": "Name of the project*", "tooltip": "", @@ -4228,9 +3790,9 @@ ] }, { - "id": "288ba4b3.a9a2cc", + "id": "9b3f7b46.107718", "type": "ui_text_input", - "z": "efeebffd.34c7e", + "z": "5c6dd7ee.546fa8", "name": "sample_id", "label": "ID of the station*", "tooltip": "", @@ -4249,9 +3811,9 @@ ] }, { - "id": "78f5791d.946bd8", + "id": "730e3aa0.75f6dc", "type": "function", - "z": "efeebffd.34c7e", + "z": "5c6dd7ee.546fa8", "name": "get sample_projet", "func": "msg.payload = msg.payload.sample_project;\nreturn msg;", "outputs": 1, @@ -4260,14 +3822,14 @@ "y": 40, "wires": [ [ - "1cb896c7.6dfc11" + "419967b7.b9b5f" ] ] }, { - "id": "2a09d440.119154", + "id": "77454044.f47e88", "type": "function", - "z": "efeebffd.34c7e", + "z": "5c6dd7ee.546fa8", "name": "get sample_ship", "func": "msg.payload = msg.payload.sample_ship;\nreturn msg;", "outputs": 1, @@ -4276,14 +3838,14 @@ "y": 120, "wires": [ [ - "10f1e5c1.3cb69a" + "6f24740b.fbae5c" ] ] }, { - "id": "346d141f.ebab3c", + "id": "b49441ee.07b358", "type": "function", - "z": "efeebffd.34c7e", + "z": "5c6dd7ee.546fa8", "name": "get sample_id", "func": "msg.payload = msg.payload.sample_id+1;\nreturn msg;", "outputs": 1, @@ -4292,14 +3854,14 @@ "y": 80, "wires": [ [ - "288ba4b3.a9a2cc" + "9b3f7b46.107718" ] ] }, { - "id": "2d438355.ed942c", + "id": "203e3416.6c480c", "type": "function", - "z": "efeebffd.34c7e", + "z": "5c6dd7ee.546fa8", "name": "get sample_operator", "func": "msg.payload = msg.payload.sample_operator;\nreturn msg;", "outputs": 1, @@ -4308,14 +3870,14 @@ "y": 160, "wires": [ [ - "aa90b06d.ca78e" + "bf7a47c8.a960b8" ] ] }, { - "id": "ac4a71a.c35309", + "id": "3555467a.6ba1ea", "type": "function", - "z": "efeebffd.34c7e", + "z": "5c6dd7ee.546fa8", "name": "get sample_sampling_gear", "func": "msg.payload = msg.payload.sample_sampling_gear;\nreturn msg;", "outputs": 1, @@ -4324,14 +3886,42 @@ "y": 200, "wires": [ [ - "da0c5a96.74c0e" + "327afe96.262122" ] ] }, { - "id": "45482528.43f93c", + "id": "417f91c9.193ab", + "type": "ui_group", + "z": "", + "name": "Sample metadata", + "tab": "2b97fe34.a699fa", + "order": 2, + "disp": true, + "width": "24", + "collapse": false + }, + { + "id": "2b97fe34.a699fa", + "type": "ui_tab", + "z": "", + "name": "GUI", + "icon": "fa-eyedropper", + "order": 2, + "disabled": false, + "hidden": false + }, + { + "id": "bb8dbe68.7e20a", + "type": "tab", + "label": "Main", + "disabled": false, + "info": "" + }, + { + "id": "20340bb6.5f923c", "type": "function", - "z": "ff9251a5.9c5e18", + "z": "bb8dbe68.7e20a", "name": "get global", "func": "msg.payload={\n \n \"sample_project\":global.get(\"sample_project\"),\n \"sample_id\":global.get(\"sample_id\"),\n \"sample_ship\":global.get(\"sample_ship\"),\n \"sample_operator\":global.get(\"sample_operator\"),\n \"sample_sampling_gear\":global.get(\"sample_sampling_gear\"),\n \n \"acq_id\":global.get(\"acq_id\"),\n \"acq_instrument\":global.get(\"acq_instrument\"),\n //\"acq_instrument_id\":global.get(\"acq_instrument_id\"),\n \"acq_celltype\":global.get(\"acq_celltype\"),\n \"acq_minimum_mesh\":global.get(\"acq_minimum_mesh\"),\n \"acq_maximum_mesh\":global.get(\"acq_maximum_mesh\"),\n \"acq_min_esd\":global.get(\"acq_min_esd\"),\n \"acq_max_esd\":global.get(\"acq_max_esd\"),\n \"acq_volume\":global.get(\"acq_volume\"),\n \"acq_magnification\":global.get(\"magnification\"),\n \"acq_fnumber_objective\":global.get(\"acq_fnumber_objective\"),\n \n \"acq_camera_name\":\"Pi Camera V2.1 - 8MP\",\n \n \"object_date\":global.get(\"object_date\"),\n \"object_time\":global.get(\"object_time\"),\n \"object_lat\":global.get(\"object_lat\"),\n \"object_lon\":global.get(\"object_lon\"),\n \"object_depth_min\":global.get(\"object_depth_min\"),\n \"object_depth_max\":global.get(\"object_depth_max\"),\n \n \"custom_nb_frame\":global.get(\"custom_nb_frame\"),\n \"custom_nb_step\":global.get(\"custom_nb_step\"),\n \"custom_segmentation\":global.get(\"custom_segmentation\"),\n \"custom_sleep_before\":global.get(\"custom_sleep_before\"),\n \"focus_nb_step\":global.get(\"focus_nb_step\"),\n \"pump_flowrate\":global.get(\"pump_flowrate\"),\n \"pump_manual_volume\":global.get(\"pump_manual_volume\"),\n \n \"process_pixel\":global.get(\"process_pixel\"),\n \"process_id\":global.get(\"process_id\")\n \n \n};\nreturn msg;", "outputs": 1, @@ -4340,14 +3930,14 @@ "y": 160, "wires": [ [ - "fe81be99.6859e8" + "d69f0eb1.d514d" ] ] }, { - "id": "a5f18550.68466", + "id": "aed82ae1.3a7558", "type": "file", - "z": "ff9251a5.9c5e18", + "z": "bb8dbe68.7e20a", "name": "", "filename": "/home/pi/PlanktonScope/config.json", "appendNewline": true, @@ -4361,9 +3951,9 @@ ] }, { - "id": "fe81be99.6859e8", + "id": "d69f0eb1.d514d", "type": "json", - "z": "ff9251a5.9c5e18", + "z": "bb8dbe68.7e20a", "name": "config.json", "property": "payload", "action": "str", @@ -4372,14 +3962,14 @@ "y": 160, "wires": [ [ - "a5f18550.68466" + "aed82ae1.3a7558" ] ] }, { - "id": "b24cc280.5a59b", + "id": "b57ab8b0.7bfc4", "type": "file in", - "z": "ff9251a5.9c5e18", + "z": "bb8dbe68.7e20a", "name": "", "filename": "/home/pi/PlanktonScope/config.json", "format": "utf8", @@ -4390,15 +3980,15 @@ "y": 80, "wires": [ [ - "11e5237b.e558c5" + "5b6059c3.8d4fa8" ] ], "info": "# PlanktonScope Help\nThis Node will read the content of the file named **config.txt** containing all the input placeholders.\n" }, { - "id": "4c6084c.1b7bb7c", + "id": "7880a269.4817ac", "type": "inject", - "z": "ff9251a5.9c5e18", + "z": "bb8dbe68.7e20a", "name": "on_load", "topic": "", "payload": "", @@ -4411,17 +4001,18 @@ "y": 80, "wires": [ [ - "b24cc280.5a59b", - "845bb10c.d99208", - "a01c8373.701628" + "b57ab8b0.7bfc4", + "10d8393.60498c7", + "dba45961.85d67", + "8231cfcc.0c5dd8" ] ], "info": "# PlanktonScope Help\nWhen the **Pi** is booting, **Node-RED** will be initiated and this node will be activated once and execute the following nodes." }, { - "id": "11e5237b.e558c5", + "id": "5b6059c3.8d4fa8", "type": "json", - "z": "ff9251a5.9c5e18", + "z": "bb8dbe68.7e20a", "name": "config.json", "property": "payload", "action": "", @@ -4430,20 +4021,20 @@ "y": 80, "wires": [ [ - "9dc8498a.4a36b", - "9b67b810.97a618", - "32282348.35c09c", - "fe7c0e45.ee983", - "3e6ceaa0.5fad56", - "9e577327.d9a1f", - "c50792f5.6b5148" + "9b872b59.667ee", + "67bab5e1.2c7dcc", + "8e5a1fb0.dc878", + "bfc59fc4.be21a8", + "80434aac.22226", + "a3453d30.ca9a28", + "e25e094c.60fb1" ] ] }, { - "id": "f72f54db.590c9", + "id": "1b45a311.c993ed", "type": "function", - "z": "ff9251a5.9c5e18", + "z": "bb8dbe68.7e20a", "name": "set global", "func": "var value = msg.payload;\nvar key = msg.topic;\n\nglobal.set(key,value);\nreturn msg;", "outputs": 1, @@ -4452,14 +4043,14 @@ "y": 80, "wires": [ [ - "45482528.43f93c" + "20340bb6.5f923c" ] ] }, { - "id": "2372125a.7f69d6", + "id": "1d54c0bf.fbcf07", "type": "rpi-gpio out", - "z": "ff9251a5.9c5e18", + "z": "bb8dbe68.7e20a", "name": "", "pin": "40", "set": "", @@ -4471,9 +4062,9 @@ "wires": [] }, { - "id": "bae08e6f.11bc28", + "id": "7da863d0.f7d41c", "type": "ui_template", - "z": "ff9251a5.9c5e18", + "z": "bb8dbe68.7e20a", "group": "dc721eb.9ef51e", "name": "Stream Pi Camera", "order": 1, @@ -4483,16 +4074,16 @@ "storeOutMessages": true, "fwdInMessages": true, "templateScope": "local", - "x": 850, + "x": 830, "y": 320, "wires": [ [] ] }, { - "id": "845bb10c.d99208", + "id": "10d8393.60498c7", "type": "function", - "z": "ff9251a5.9c5e18", + "z": "bb8dbe68.7e20a", "name": "init LED", "func": "msg.payload=1;\nreturn msg;", "outputs": 1, @@ -4501,149 +4092,139 @@ "y": 120, "wires": [ [ - "2372125a.7f69d6" + "1d54c0bf.fbcf07" ] ] }, { - "id": "9dc8498a.4a36b", - "type": "subflow:efeebffd.34c7e", - "z": "ff9251a5.9c5e18", + "id": "9b872b59.667ee", + "type": "subflow:5c6dd7ee.546fa8", + "z": "bb8dbe68.7e20a", "name": "", "env": [], "x": 830, "y": 80, "wires": [ [ - "f72f54db.590c9" + "1b45a311.c993ed" ] ] }, { - "id": "9e577327.d9a1f", - "type": "subflow:5c516299.73e054", - "z": "ff9251a5.9c5e18", + "id": "a3453d30.ca9a28", + "type": "subflow:ac806d39.1682a8", + "z": "bb8dbe68.7e20a", "name": "", "env": [], - "x": 846, - "y": 242, + "x": 820, + "y": 240, "wires": [ [ - "f72f54db.590c9" + "1b45a311.c993ed" ] ] }, { - "id": "c50792f5.6b5148", - "type": "subflow:626459d2.f9c98", - "z": "ff9251a5.9c5e18", + "id": "e25e094c.60fb1", + "type": "subflow:9a45991b.365bc8", + "z": "bb8dbe68.7e20a", "name": "", "env": [], - "x": 846, - "y": 282, + "x": 820, + "y": 280, "wires": [ [ - "f72f54db.590c9" + "1b45a311.c993ed" ] ] }, { - "id": "9b67b810.97a618", - "type": "subflow:6ca1a253.126bb4", - "z": "ff9251a5.9c5e18", + "id": "67bab5e1.2c7dcc", + "type": "subflow:97d77aeb.75afd8", + "z": "bb8dbe68.7e20a", "name": "", "env": [], "x": 840, "y": 120, "wires": [ [ - "f72f54db.590c9" + "1b45a311.c993ed" ], [ - "45482528.43f93c" + "20340bb6.5f923c" ] ] }, { - "id": "32282348.35c09c", - "type": "subflow:b45c6fb6.f6dfa8", - "z": "ff9251a5.9c5e18", + "id": "8e5a1fb0.dc878", + "type": "subflow:506e9090.6e905", + "z": "bb8dbe68.7e20a", "name": "", "env": [], "x": 820, "y": 160, "wires": [ [ - "f72f54db.590c9" + "1b45a311.c993ed" ], [ - "45482528.43f93c" + "20340bb6.5f923c" ] ] }, { - "id": "8e1d0d8d.fc54d8", - "type": "subflow:fbe9590f.bd63b8", - "z": "ff9251a5.9c5e18", + "id": "14b78383.7457bc", + "type": "subflow:1273b673.4a35ea", + "z": "bb8dbe68.7e20a", "name": "System commands", "env": [], - "x": 850, - "y": 500, + "x": 830, + "y": 480, "wires": [] }, { - "id": "f8a906b3.a2c81", - "type": "subflow:9882c53a.0ccc8", - "z": "ff9251a5.9c5e18", + "id": "e6403eaf.54f7e", + "type": "subflow:246abd43.838a5a", + "z": "bb8dbe68.7e20a", "name": "", "env": [], - "x": 320, - "y": 280, + "x": 840, + "y": 400, "wires": [] }, { - "id": "b1be7e1e.9ec3c8", - "type": "subflow:a8ad6dec.1a393", - "z": "ff9251a5.9c5e18", - "name": "", - "env": [], - "x": 850, - "y": 420, - "wires": [] - }, - { - "id": "fe7c0e45.ee983", - "type": "subflow:5a287804.a10e2", - "z": "ff9251a5.9c5e18", + "id": "bfc59fc4.be21a8", + "type": "subflow:99798a85.e62408", + "z": "bb8dbe68.7e20a", "name": "process metadata", "env": [], "x": 830, "y": 200, "wires": [ [ - "f72f54db.590c9" + "1b45a311.c993ed" ] ] }, { - "id": "3e6ceaa0.5fad56", - "type": "subflow:863e8384.56889", - "z": "ff9251a5.9c5e18", + "id": "80434aac.22226", + "type": "subflow:a156df1e.d37178", + "z": "bb8dbe68.7e20a", "name": "Acquisition inputs", "env": [], - "x": 836, - "y": 362, + "x": 830, + "y": 360, "wires": [ [ - "f72f54db.590c9" + "1b45a311.c993ed" ] ], "icon": "node-red-dashboard/ui_switch.png" }, { - "id": "a01c8373.701628", - "type": "subflow:c10e968b.87e488", - "z": "ff9251a5.9c5e18", + "id": "dba45961.85d67", + "type": "subflow:6384a5e.e34465c", + "z": "bb8dbe68.7e20a", "name": "", "env": [], "x": 300, @@ -4651,9 +4232,9 @@ "wires": [] }, { - "id": "1924ce1c.0459f2", - "type": "subflow:c1d3ff7c.4384f", - "z": "ff9251a5.9c5e18", + "id": "8231cfcc.0c5dd8", + "type": "subflow:e8320d42.9a3ad8", + "z": "bb8dbe68.7e20a", "name": "", "env": [], "x": 290, @@ -4661,19 +4242,19 @@ "wires": [] }, { - "id": "d3892f94.428a28", - "type": "subflow:bba19d97.b32b1", - "z": "ff9251a5.9c5e18", + "id": "557afe0d.33d97", + "type": "subflow:97600dff.93378", + "z": "bb8dbe68.7e20a", "name": "", "env": [], - "x": 850, - "y": 460, + "x": 830, + "y": 440, "wires": [] }, { - "id": "e73525a.1103158", + "id": "af4f780b.068368", "type": "ui_switch", - "z": "ff9251a5.9c5e18", + "z": "bb8dbe68.7e20a", "name": "", "label": "LED", "tooltip": "", @@ -4697,167 +4278,19 @@ "y": 160, "wires": [ [ - "2372125a.7f69d6" + "1d54c0bf.fbcf07" ] ] }, { - "id": "be37d12f.0898f", - "type": "file", - "z": "c1d3ff7c.4384f", - "name": "", - "filename": "/home/pi/PlanktonScope/script/main.py", - "appendNewline": false, - "createDir": true, - "overwriteFile": "true", - "encoding": "none", - "x": 530, - "y": 100, - "wires": [ - [ - "23f3e613.20ad82" - ] - ] - }, - { - "id": "49e31e85.7ac51", - "type": "template", - "z": "c1d3ff7c.4384f", - "name": "main.py", - "field": "payload", - "fieldType": "msg", - "format": "python", - "syntax": "plain", - "template": "################################################################################\n#Actuator Libraries\n################################################################################\n\n#Library for exchaning messages with Node-RED\nimport paho.mqtt.client as mqtt\n\n#Library to control the PiCamera\nfrom picamera import PiCamera\n\n#Libraries to control the steppers for focusing and pumping\nfrom adafruit_motor import stepper\nfrom adafruit_motorkit import MotorKit\n\n#Library to send command over I2C for the light module on the fan\nimport smbus\n\n################################################################################\n#Practical Libraries\n################################################################################\n\n#Library to get date and time for folder name and filename\nfrom datetime import datetime, timedelta\n\n#Library to be able to sleep for a duration\nfrom time import sleep\n\n#Libraries manipulate json format, execute bash commands\nimport json, shutil, os, subprocess\n\n################################################################################\n#Morphocut Libraries\n################################################################################\n\nfrom skimage.util import img_as_ubyte\nfrom morphocut import Call\nfrom morphocut.contrib.ecotaxa import EcotaxaWriter\nfrom morphocut.contrib.zooprocess import CalculateZooProcessFeatures\nfrom morphocut.core import Pipeline\nfrom morphocut.file import Find\nfrom morphocut.image import (ExtractROI,\n FindRegions,\n ImageReader,\n ImageWriter,\n RescaleIntensity,\n RGB2Gray\n)\nfrom morphocut.stat import RunningMedian\nfrom morphocut.str import Format\nfrom morphocut.stream import TQDM, Enumerate, FilterVariables\n\n################################################################################\n#Other image processing Libraries\n################################################################################\n\nfrom skimage.feature import canny\nfrom skimage.color import rgb2gray, label2rgb\nfrom skimage.morphology import disk\nfrom skimage.morphology import erosion, dilation, closing\nfrom skimage.measure import label, regionprops\nimport cv2\n\n################################################################################\n#Streaming PiCamera over server\n################################################################################\nimport io\nimport picamera\nimport logging\nimport socketserver\nfrom threading import Condition\nfrom http import server\nimport threading\n\n################################################################################\n#Creation of the webpage containing the PiCamera Streaming\n################################################################################\n\nPAGE=\"\"\"\\\n\n\nPlanktonScope v2 | PiCamera Streaming\n\n\n\n\n\n\"\"\"\n\n################################################################################\n#Classes for the PiCamera Streaming\n################################################################################\n\nclass StreamingOutput(object):\n def __init__(self):\n self.frame = None\n self.buffer = io.BytesIO()\n self.condition = Condition()\n\n def write(self, buf):\n if buf.startswith(b'\\xff\\xd8'):\n # New frame, copy the existing buffer's content and notify all\n # clients it's available\n self.buffer.truncate()\n with self.condition:\n self.frame = self.buffer.getvalue()\n self.condition.notify_all()\n self.buffer.seek(0)\n return self.buffer.write(buf)\n\nclass StreamingHandler(server.BaseHTTPRequestHandler):\n def do_GET(self):\n if self.path == '/':\n self.send_response(301)\n self.send_header('Location', '/index.html')\n self.end_headers()\n elif self.path == '/index.html':\n content = PAGE.encode('utf-8')\n self.send_response(200)\n self.send_header('Content-Type', 'text/html')\n self.send_header('Content-Length', len(content))\n self.end_headers()\n self.wfile.write(content)\n elif self.path == '/stream.mjpg':\n self.send_response(200)\n self.send_header('Age', 0)\n self.send_header('Cache-Control', 'no-cache, private')\n self.send_header('Pragma', 'no-cache')\n self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME')\n self.end_headers()\n try:\n while True:\n with output.condition:\n output.condition.wait()\n frame = output.frame\n self.wfile.write(b'--FRAME\\r\\n')\n self.send_header('Content-Type', 'image/jpeg')\n self.send_header('Content-Length', len(frame))\n self.end_headers()\n self.wfile.write(frame)\n self.wfile.write(b'\\r\\n')\n except Exception as e:\n logging.warning(\n 'Removed streaming client %s: %s',\n self.client_address, str(e))\n else:\n self.send_error(404)\n self.end_headers()\n\nclass StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer):\n allow_reuse_address = True\n daemon_threads = True\n\n################################################################################\n#MQTT core functions\n################################################################################\n\n#Run this function in order to connect to the client (Node-RED)\ndef on_connect(client, userdata, flags, rc):\n #Print when connected\n print(\"Connected! - \" + str(rc))\n #When connected, run subscribe()\n client.subscribe(\"actuator/#\")\n #Turn green the light module\n rgb(0,255,0)\n\n#Run this function in order to subscribe to all the topics begining by actuator\ndef on_subscribe(client, obj, mid, granted_qos):\n #Print when subscribed\n print(\"Subscribed! - \"+str(mid)+\" \"+str(granted_qos))\n\n#Run this command when Node-RED is sending a message on the subscribed topic\ndef on_message(client, userdata, msg):\n #Print the topic and the message\n print(msg.topic+\" \"+str(msg.qos)+\" \"+str(msg.payload))\n #Update the global variables command, args and counter\n global command\n global args\n global counter\n #Parse the topic to find the command. ex : actuator/pump -> pump\n command=msg.topic.split(\"/\")[1]\n #Decode the message to find the arguments\n args=str(msg.payload.decode())\n #Reset the counter to 0\n counter=0\n\n################################################################################\n#LEDs Actuation\n################################################################################\ndef rgb(R,G,B):\n #Update LED n1\n bus.write_byte_data(0x0d, 0x00, 0)\n bus.write_byte_data(0x0d, 0x01, R)\n bus.write_byte_data(0x0d, 0x02, G)\n bus.write_byte_data(0x0d, 0x03, B)\n\n #Update LED n2\n bus.write_byte_data(0x0d, 0x00, 1)\n bus.write_byte_data(0x0d, 0x01, R)\n bus.write_byte_data(0x0d, 0x02, G)\n bus.write_byte_data(0x0d, 0x03, B)\n\n #Update LED n3\n bus.write_byte_data(0x0d, 0x00, 2)\n bus.write_byte_data(0x0d, 0x01, R)\n bus.write_byte_data(0x0d, 0x02, G)\n bus.write_byte_data(0x0d, 0x03, B)\n\n #Update the I2C Bus in order to really update the LEDs new values\n cmd=\"i2cdetect -y 1\"\n subprocess.Popen(cmd.split(),stdout=subprocess.PIPE)\n\n################################################################################\n#Init function - executed only once\n################################################################################\n\n#define the bus used to actuate the light module on the fan\nbus = smbus.SMBus(1)\n\n#define the names for the 2 exsting steppers\nkit = MotorKit()\npump_stepper = kit.stepper1\nfocus_stepper = kit.stepper2\n#Make sure the steppers are release and do not use any power\npump_stepper.release()\nfocus_stepper.release()\n\n#Precise the settings of the PiCamera\ncamera = PiCamera()\ncamera.resolution = (3280, 2464)\ncamera.iso = 60\ncamera.shutter_speed = 500\ncamera.exposure_mode = 'fixedfps'\n\n#Declare the global variables command, args and counter\ncommand = ''\nargs = ''\ncounter=''\n\n#MQTT Client functions definition\nclient = mqtt.Client()\nclient.connect(\"192.168.4.1\",1883,60)\nclient.on_connect = on_connect\nclient.on_subscribe = on_subscribe\nclient.on_message = on_message\nclient.loop_start()\n\n################################################################################\n#Definition of the few important metadata\n################################################################################\n\nlocal_metadata = {\n \"process_datetime\": datetime.now(),\n \"acq_camera_resolution\" : camera.resolution,\n \"acq_camera_iso\" : camera.iso,\n \"acq_camera_shutter_speed\" : camera.shutter_speed\n}\n\n#Read the content of config.json containing the metadata defined on Node-RED\nconfig_json = open('/home/pi/PlanktonScope/config.json','r')\nnode_red_metadata = json.loads(config_json.read())\n\n#Concat the local metadata and the metadata from Node-RED\nglobal_metadata = {**local_metadata, **node_red_metadata}\n\n#Define the name of the .zip file that will contain the images and the .tsv table for EcoTaxa\narchive_fn = os.path.join(\"/home/pi/PlanktonScope/\",\"export\", \"ecotaxa_export.zip\")\n\n################################################################################\n#MorphoCut Script\n################################################################################\n\n#Define processing pipeline\nwith Pipeline() as p:\n\n #Recursively find .jpg files in import_path.\n #Sort to get consective frames.\n abs_path = Find(\"/home/pi/PlanktonScope/tmp\", [\".jpg\"], sort=True, verbose=True)\n\n #Extract name from abs_path\n name = Call(lambda p: os.path.splitext(os.path.basename(p))[0], abs_path)\n\n #Set the LEDs as Green\n Call(rgb, 0,255,0)\n\n #Read image\n img = ImageReader(abs_path)\n\n #Show progress bar for frames\n TQDM(Format(\"Frame {name}\", name=name))\n\n #Apply running median to approximate the background image\n flat_field = RunningMedian(img, 5)\n\n #Correct image\n img = img / flat_field\n\n #Rescale intensities and convert to uint8 to speed up calculations\n img = RescaleIntensity(img, in_range=(0, 1.1), dtype=\"uint8\")\n\n #Filter variable to reduce memory load\n FilterVariables(name,img)\n\n #Save cleaned images\n #frame_fn = Format(os.path.join(\"/home/pi/PlanktonScope/tmp\",\"CLEAN\", \"{name}.jpg\"), name=name)\n #ImageWriter(frame_fn, img)\n\n #Convert image to uint8 gray\n img_gray = RGB2Gray(img)\n\n #?\n img_gray = Call(img_as_ubyte, img_gray)\n\n #Canny edge detection using OpenCV\n img_canny = Call(cv2.Canny, img_gray, 50,100)\n\n #Dilate using OpenCV\n kernel = Call(cv2.getStructuringElement, cv2.MORPH_ELLIPSE, (15, 15))\n img_dilate = Call(cv2.dilate, img_canny, kernel, iterations=2)\n\n #Close using OpenCV\n kernel = Call(cv2.getStructuringElement, cv2.MORPH_ELLIPSE, (5, 5))\n img_close = Call(cv2.morphologyEx, img_dilate, cv2.MORPH_CLOSE, kernel, iterations=1)\n\n #Erode using OpenCV\n kernel = Call(cv2.getStructuringElement, cv2.MORPH_ELLIPSE, (15, 15))\n mask = Call(cv2.erode, img_close, kernel, iterations=2)\n\n #Find objects\n regionprops = FindRegions(\n mask, img_gray, min_area=1000, padding=10, warn_empty=name\n )\n\n #Set the LEDs as Purple\n Call(rgb, 255,0,255)\n\n # For an object, extract a vignette/ROI from the image\n roi_orig = ExtractROI(img, regionprops, bg_color=255)\n\n # Generate an object identifier\n i = Enumerate()\n\n #Call(print,i)\n\n #Define the ID of each object\n object_id = Format(\"{name}_{i:d}\", name=name, i=i)\n\n #Call(print,object_id)\n\n #Define the name of each object\n object_fn = Format(os.path.join(\"/home/pi/PlanktonScope/\",\"OBJECTS\", \"{name}.jpg\"), name=object_id)\n\n #Save the image of the object with its name\n ImageWriter(object_fn, roi_orig)\n\n #Calculate features. The calculated features are added to the global_metadata.\n #Returns a Variable representing a dict for every object in the stream.\n meta = CalculateZooProcessFeatures(\n regionprops, prefix=\"object_\", meta=global_metadata\n )\n\n #Get all the metadata\n json_meta = Call(json.dumps,meta, sort_keys=True, default=str)\n\n #Publish the json containing all the metadata to via MQTT to Node-RED\n Call(client.publish, \"receiver/segmentation/metric\", json_meta)\n\n #Add object_id to the metadata dictionary\n meta[\"object_id\"] = object_id\n\n #Generate object filenames\n orig_fn = Format(\"{object_id}.jpg\", object_id=object_id)\n\n #Write objects to an EcoTaxa archive:\n #roi image in original color, roi image in grayscale, metadata associated with each object\n EcotaxaWriter(archive_fn, (orig_fn, roi_orig), meta)\n\n #Progress bar for objects\n TQDM(Format(\"Object {object_id}\", object_id=object_id))\n\n #Publish the object_id to via MQTT to Node-RED\n Call(client.publish, \"receiver/segmentation/object_id\", object_id)\n\n #Set the LEDs as Green\n Call(rgb, 0,255,0)\n\n################################################################################\n#While loop for capting commands from Node-RED\n################################################################################\n\noutput = StreamingOutput()\naddress = ('192.168.4.1', 8000)\nserver = StreamingServer(address, StreamingHandler)\nthreading.Thread(target=server.serve_forever).start()\ncamera.start_recording(output, format='mjpeg', resize=(640, 480))\n\nwhile True:\n\n ############################################################################\n #Pump Event\n ############################################################################\n\n #If the command is \"pump\"\n if (command==\"pump\"):\n\n #Set the LEDs as Blue\n rgb(0,0,255)\n\n #Get direction from the different received arguments\n direction=args.split(\" \")[0]\n\n #Get delay (in between steps) from the different received arguments\n delay=float(args.split(\" \")[1])\n\n #Get number of steps from the different received arguments\n nb_step=int(args.split(\" \")[2])\n\n #Print status\n print(\"The pump has been started.\")\n\n #Publish the status \"Start\" to via MQTT to Node-RED\n client.publish(\"receiver/pump\", \"Start\");\n\n ########################################################################\n while True:\n\n #Depending on direction, select the right direction for the pump\n if direction == \"BACKWARD\":\n direction=stepper.BACKWARD\n\n if direction == \"FORWARD\":\n direction=stepper.FORWARD\n\n #Actuate the pump for one step in the right direction\n pump_stepper.onestep(direction=direction, style=stepper.DOUBLE)\n\n #Increment the counter\n counter+=1\n\n #Wait during the delay to pump at the right flowrate\n sleep(delay)\n\n ####################################################################\n #If counter reach the number of step, break\n if counter>nb_step:\n\n #Release the pump stepper to stop power draw\n pump_stepper.release()\n\n #Print status\n print(\"The pumping is done.\")\n\n #Change the command to not re-enter in this while loop\n command=\"wait\"\n\n #Publish the status \"Done\" to via MQTT to Node-RED\n client.publish(\"receiver/pump\", \"Done\");\n\n #Set the LEDs as Green\n rgb(0,255,0)\n\n #Reset the counter to 0\n counter=0\n\n break\n\n ####################################################################\n #If a new received command isn't \"pump\", break this while loop\n if command!=\"pump\":\n\n #Release the pump stepper to stop power draw\n pump_stepper.release()\n\n #Print status\n print(\"The pump has been interrompted.\")\n\n #Publish the status \"Interrompted\" to via MQTT to Node-RED\n client.publish(\"receiver/pump\", \"Interrompted\");\n\n #Set the LEDs as Green\n rgb(0,255,0)\n\n #Reset the counter to 0\n counter=0\n\n break\n\n ############################################################################\n #Focus Event\n ############################################################################\n\n #If the command is \"focus\"\n elif (command==\"focus\"):\n\n #Set the LEDs as Yellow\n rgb(255,255,0)\n\n #Get direction from the different received arguments\n direction=args.split(\" \")[0]\n\n #Get number of steps from the different received arguments\n nb_step=int(args.split(\" \")[1])\n\n #Print status\n print(\"The focus has been started.\")\n\n #Publish the status \"Start\" to via MQTT to Node-RED\n client.publish(\"receiver/focus\", \"Start\");\n\n ########################################################################\n while True:\n\n #Depending on direction, select the right direction for the focus\n if direction == \"FORWARD\":\n direction=stepper.FORWARD\n\n if direction == \"BACKWARD\":\n direction=stepper.BACKWARD\n\n #Actuate the focus for one microstep in the right direction\n focus_stepper.onestep(direction=direction, style=stepper.MICROSTEP)\n\n #Increment the counter\n counter+=1\n\n ####################################################################\n #If counter reach the number of step, break\n if counter>nb_step:\n\n #Release the focus steppers to stop power draw\n focus_stepper.release()\n\n #Print status\n print(\"The focusing is done.\")\n\n #Change the command to not re-enter in this while loop\n command=\"wait\"\n\n #Publish the status \"Done\" to via MQTT to Node-RED\n client.publish(\"receiver/focus\", \"Done\");\n\n #Set the LEDs as Green\n rgb(0,255,0)\n\n #Reset the counter to 0\n counter=0\n\n break\n\n ####################################################################\n #If a new received command isn't \"pump\", break this while loop\n if command!=\"focus\":\n\n #Release the focus steppers to stop power draw\n focus_stepper.release()\n\n #Print status\n print(\"The stage has been interrompted.\")\n\n #Publish the status \"Done\" to via MQTT to Node-RED\n client.publish(\"receiver/focus\", \"Interrompted\");\n\n #Set the LEDs as Green\n rgb(0,255,0)\n\n #Reset the counter to 0\n counter=0\n\n break\n\n ############################################################################\n #Image Event\n ############################################################################\n\n elif (command==\"image\"):\n \n #Publish the status \"Start\" to via MQTT to Node-RED\n client.publish(\"receiver/image\", \"Will do my best dude\");\n\n #Get duration to wait before an image from the different received arguments\n sleep_before=int(args.split(\" \")[0])\n\n #Get number of step in between two images from the different received arguments\n nb_step=int(args.split(\" \")[1])\n\n #Get the number of frames to image from the different received arguments\n nb_frame=int(args.split(\" \")[2])\n\n #Get the segmentation status (true/false) from the different received arguments\n segmentation=str(args.split(\" \")[3])\n\n #Sleep a duration before to start acquisition\n sleep(sleep_before)\n\n #Publish the status \"Start\" to via MQTT to Node-RED\n client.publish(\"receiver/image\", \"Start\");\n\n #Set the LEDs as Blue\n rgb(0,0,255)\n\n #Pump duing a given number of steps (in between each image)\n for i in range(nb_step):\n\n #If the command is still image - pump a defined nb of steps\n if (command==\"image\"):\n\n #Actuate the pump for one step in the FORWARD direction\n pump_stepper.onestep(direction=stepper.FORWARD, style=stepper.DOUBLE)\n\n #The flowrate is fixed for now.\n sleep(0.01)\n\n #If the command isn't image anymore - break\n else:\n\n break\n\n #Set the LEDs as Green\n rgb(0,255,0)\n\n while True:\n\n #Set the LEDs as Cyan\n rgb(0,255,255)\n\n #Increment the counter\n counter+=1\n\n #Get datetime\n datetime_tmp=datetime.now().strftime(\"%H_%M_%S_%f\")\n\n #Print datetime\n print(datetime_tmp)\n\n #Define the filename of the image\n filename = os.path.join(\"/home/pi/PlanktonScope/tmp\",datetime_tmp+\".jpg\")\n\n #Capture an image with the proper filename\n camera.capture(filename)\n\n #Set the LEDs as Green\n rgb(0,255,0)\n\n #Publish the name of the image to via MQTT to Node-RED\n\n client.publish(\"receiver/image\", datetime_tmp+\".jpg has been imaged.\");\n \n #Set the LEDs as Blue\n rgb(0,0,255)\n\n #Pump during a given nb of steps\n for i in range(nb_step):\n\n #Actuate the pump for one step in the FORWARD direction\n pump_stepper.onestep(direction=stepper.FORWARD, style=stepper.DOUBLE)\n\n #The flowrate is fixed for now.\n sleep(0.01)\n\n #Wait a fixed delay which set the framerate as < than 2 imag/sec\n sleep(0.5)\n\n #Set the LEDs as Green\n rgb(0,255,0)\n\n ####################################################################\n #If counter reach the number of frame, break\n if(counter>nb_frame):\n\n #Publish the status \"Completed\" to via MQTT to Node-RED\n client.publish(\"receiver/image\", \"Completed\");\n\n #Release the pump steppers to stop power draw\n pump_stepper.release()\n\n if(segmentation == \"True\"):\n\n #Publish the status \"Start\" to via MQTT to Node-RED\n client.publish(\"receiver/segmentation\", \"Start\");\n\n #Start the MorphoCut Pipeline\n p.run()\n\n #remove directory\n #shutil.rmtree(import_path)\n\n #Publish the status \"Completed\" to via MQTT to Node-RED\n client.publish(\"receiver/segmentation\", \"Completed\");\n\n #Set the LEDs as White\n rgb(255,255,255)\n\n #cmd = os.popen(\"rm -rf /home/pi/PlanktonScope/tmp/*.jpg\")\n\n #Let it happen\n sleep(1)\n\n #Set the LEDs as Green\n rgb(0,255,0)\n\n #End if(segmentation == \"True\"):\n\n #Change the command to not re-enter in this while loop\n command=\"wait\"\n \n #Set the LEDs as Green\n rgb(0,255,255)\n\n #Reset the counter to 0\n counter=0\n\n break\n\n ####################################################################\n #If a new received command isn't \"image\", break this while loop\n if command!=\"image\":\n\n #Release the pump steppers to stop power draw\n pump_stepper.release()\n\n #Print status\n print(\"The imaging has been interrompted.\")\n\n #Publish the status \"Interrompted\" to via MQTT to Node-RED\n client.publish(\"receiver/image\", \"Interrompted\");\n\n #Set the LEDs as Green\n rgb(0,255,0)\n\n #Reset the counter to 0\n counter=0\n\n break\n\n else:\n #Set the LEDs as Black\n rgb(0,0,0)\n #Its just waiting to receive command from Node-RED\n sleep(1)\n #Set the LEDs as White\n rgb(255,255,255)\n #Its just waiting to receive command from Node-RED\n sleep(1)\n", - "output": "str", - "x": 300, - "y": 100, - "wires": [ - [ - "be37d12f.0898f" - ] - ] - }, - { - "id": "f9705bc.3d322a8", - "type": "ui_switch", - "z": "863e8384.56889", - "name": "custom_segmentation", - "label": "Realize the segmentation", - "tooltip": "", - "group": "48649115.fcd01", - "order": 6, - "width": 0, - "height": 0, - "passthru": true, - "decouple": "false", - "topic": "custom_segmentation", - "style": "", - "onvalue": "True", - "onvalueType": "str", - "onicon": "", - "oncolor": "", - "offvalue": "False", - "offvalueType": "str", - "officon": "", - "offcolor": "", - "x": 520, - "y": 160, - "wires": [ - [] - ] - }, - { - "id": "2de12b49.050f44", - "type": "debug", - "z": "c1d3ff7c.4384f", - "name": "", - "active": true, - "tosidebar": true, - "console": false, - "tostatus": false, - "complete": "true", - "targetType": "full", - "x": 1230, - "y": 200, - "wires": [] - }, - { - "id": "5079cccb.298d14", - "type": "exec", - "z": "c1d3ff7c.4384f", - "command": "ps -ax | grep \"python3.7 /home/pi/PlanktonScope/script/main.py\"| head -1 | awk -F \" \" '{print$1}' ", - "addpay": false, - "append": "", - "useSpawn": "false", - "timer": "", - "oldrc": false, - "name": "", - "x": 430, - "y": 40, - "wires": [ - [ - "c47c2122.5eea38" - ], - [], - [] - ] - }, - { - "id": "c47c2122.5eea38", - "type": "exec", - "z": "c1d3ff7c.4384f", - "command": "kill", - "addpay": true, - "append": "", - "useSpawn": "false", - "timer": "", - "oldrc": false, - "name": "", - "x": 910, - "y": 40, - "wires": [ - [], - [], - [] - ] - }, - { - "id": "197215b2.165f22", - "type": "delay", - "z": "c1d3ff7c.4384f", - "name": "", - "pauseType": "delay", - "timeout": "1", - "timeoutUnits": "seconds", - "rate": "1", - "nbRateUnits": "1", - "rateUnits": "second", - "randomFirst": "1", - "randomLast": "5", - "randomUnits": "seconds", - "drop": false, - "x": 160, - "y": 100, - "wires": [ - [ - "49e31e85.7ac51" - ] - ] - }, - { - "id": "589fbae2.8ff914", - "type": "debug", - "z": "a8ad6dec.1a393", - "name": "", - "active": true, - "tosidebar": true, - "console": false, - "tostatus": false, - "complete": "true", - "targetType": "full", - "x": 240, - "y": 140, - "wires": [] + "id": "dc721eb.9ef51e", + "type": "ui_group", + "z": "", + "name": "Streaming camera", + "tab": "2b97fe34.a699fa", + "order": 3, + "disp": true, + "width": 24, + "collapse": false } ]