Skip to content
Snippets Groups Projects
Commit 32b48f0d authored by Léopold Varlamoff's avatar Léopold Varlamoff
Browse files

init commit

parent b7eb7489
No related branches found
No related tags found
No related merge requests found
[
{
"id": "27ca1ab3d111d118",
"type": "tab",
"label": "Connection & warehouse",
"disabled": false,
"info": "",
"env": []
},
{
"id": "593bb738e7507707",
"type": "tab",
"label": "Capabilities list",
"disabled": false,
"info": "",
"env": []
},
{
"id": "2bc19b2f7b518cb2",
"type": "tab",
"label": "Form",
"disabled": false,
"info": "",
"env": []
},
{
"id": "f96e455ab747ba2b",
"type": "tab",
"label": "Product feasibility",
"disabled": false,
"info": "",
"env": []
},
{
"id": "1320790a4546b4fd",
"type": "tab",
"label": "Proposition",
"disabled": false,
"info": "",
"env": []
},
{
"id": "8f5d8ce91dd46f18",
"type": "junction",
"z": "1320790a4546b4fd",
"x": 320,
"y": 380,
"wires": [
[
"0f6401f582448d0c"
]
]
},
{
"id": "2282c53e6f2d220c",
"type": "mqtt-broker",
"name": "RaspberryPi",
"broker": "192.168.200.163",
"port": "8883",
"tls": "5850cb65c596909b",
"clientid": "",
"autoConnect": true,
"usetls": true,
"protocolVersion": "4",
"keepalive": "60",
"cleansession": true,
"birthTopic": "",
"birthQos": "0",
"birthPayload": "",
"birthMsg": {},
"closeTopic": "",
"closeQos": "0",
"closePayload": "",
"closeMsg": {},
"willTopic": "",
"willQos": "0",
"willPayload": "",
"willMsg": {},
"userProps": "",
"sessionExpiry": ""
},
{
"id": "dbb23360d33d8fb4",
"type": "ui_tab",
"name": "Home",
"icon": "",
"disabled": false,
"hidden": false
},
{
"id": "1c4f96d6011aaaa5",
"type": "ui_base",
"theme": {
"name": "theme-light",
"lightTheme": {
"default": "#0094CE",
"baseColor": "#0094CE",
"baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif",
"edited": true,
"reset": false
},
"darkTheme": {
"default": "#097479",
"baseColor": "#4e6f83",
"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",
"reset": false
},
"themeState": {
"base-color": {
"default": "#0094CE",
"value": "#0094CE",
"edited": true
},
"page-titlebar-backgroundColor": {
"value": "#0094CE",
"edited": false
},
"page-backgroundColor": {
"value": "#fafafa",
"edited": false
},
"page-sidebar-backgroundColor": {
"value": "#ffffff",
"edited": false
},
"group-textColor": {
"value": "#1bbfff",
"edited": false
},
"group-borderColor": {
"value": "#ffffff",
"edited": false
},
"group-backgroundColor": {
"value": "#ffffff",
"edited": false
},
"widget-textColor": {
"value": "#111111",
"edited": false
},
"widget-backgroundColor": {
"value": "#0094ce",
"edited": false
},
"widget-borderColor": {
"value": "#ffffff",
"edited": false
},
"base-font": {
"value": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif"
}
},
"angularTheme": {
"primary": "indigo",
"accents": "blue",
"warn": "red",
"background": "grey",
"palette": "light"
}
},
"site": {
"name": "Node-RED Dashboard",
"hideToolbar": "false",
"allowSwipe": "false",
"lockMenu": "false",
"allowTempTheme": "true",
"dateFormat": "DD/MM/YYYY",
"sizes": {
"sx": 48,
"sy": 48,
"gx": 6,
"gy": 6,
"cx": 6,
"cy": 6,
"px": 0,
"py": 0
}
}
},
{
"id": "80a80175907e2ec4",
"type": "ui_group",
"name": "Capabilities",
"tab": "0ffad0ef9167997d",
"order": 2,
"disp": true,
"width": "8",
"collapse": false,
"className": ""
},
{
"id": "df9ec70032434b59",
"type": "mqtt-broker",
"name": "local (secure)",
"broker": "localhost",
"port": "8883",
"tls": "ceab5cf497e7e421",
"clientid": "",
"autoConnect": true,
"usetls": true,
"protocolVersion": "4",
"keepalive": "60",
"cleansession": true,
"birthTopic": "",
"birthQos": "0",
"birthPayload": "",
"birthMsg": {},
"closeTopic": "",
"closeQos": "0",
"closePayload": "",
"closeMsg": {},
"willTopic": "",
"willQos": "0",
"willPayload": "",
"willMsg": {},
"userProps": "",
"sessionExpiry": ""
},
{
"id": "f46a108f2a7fd47d",
"type": "ui_group",
"name": "Information",
"tab": "0ffad0ef9167997d",
"order": 2,
"disp": true,
"width": "16",
"collapse": false,
"className": ""
},
{
"id": "f0a0e923d8d71887",
"type": "ui_tab",
"name": "Data",
"icon": "",
"disabled": false,
"hidden": true
},
{
"id": "f71415c794c6ce3f",
"type": "ui_group",
"name": "Variables",
"tab": "f0a0e923d8d71887",
"order": 1,
"disp": true,
"width": "8",
"collapse": false,
"className": ""
},
{
"id": "498001e703259453",
"type": "ui_group",
"name": "Live",
"tab": "f0a0e923d8d71887",
"order": 2,
"disp": true,
"width": "12",
"collapse": false,
"className": ""
},
{
"id": "f42eda3bec77a0ec",
"type": "ui_group",
"name": "Enter your own values",
"tab": "ae7ff6cddbcae331",
"order": 2,
"disp": true,
"width": "12",
"collapse": false,
"className": ""
},
{
"id": "316f43488033c495",
"type": "ui_group",
"name": "Connected clients",
"tab": "61216f89242a96ef",
"order": 2,
"disp": true,
"width": "8",
"collapse": false,
"className": ""
},
{
"id": "ae7ff6cddbcae331",
"type": "ui_tab",
"name": "Workpiece order",
"icon": "",
"disabled": false,
"hidden": false
},
{
"id": "056d3115f1f3b8b2",
"type": "ui_group",
"name": "nothing",
"tab": "dbb23360d33d8fb4",
"order": 1,
"disp": true,
"width": "10",
"collapse": false,
"className": ""
},
{
"id": "1bea595dc9db51b7",
"type": "ui_group",
"name": "Products",
"tab": "ae7ff6cddbcae331",
"order": 2,
"disp": true,
"width": "10",
"collapse": false,
"className": ""
},
{
"id": "11c65e700ad5a74d",
"type": "ui_tab",
"name": "Proposition",
"icon": "",
"disabled": false,
"hidden": true
},
{
"id": "859d724c411b6b56",
"type": "ui_group",
"name": "Your product",
"tab": "11c65e700ad5a74d",
"order": 1,
"disp": true,
"width": "10",
"collapse": false,
"className": ""
},
{
"id": "fbf688fde095656a",
"type": "ui_tab",
"name": "Confirmation",
"icon": "",
"disabled": false,
"hidden": true
},
{
"id": "25611d1488853208",
"type": "ui_group",
"name": "Thank you for your order",
"tab": "fbf688fde095656a",
"order": 1,
"disp": true,
"width": "6",
"collapse": false,
"className": ""
},
{
"id": "0ffad0ef9167997d",
"type": "ui_tab",
"name": "Capabilities",
"icon": "dashboard",
"disabled": false,
"hidden": true
},
{
"id": "61216f89242a96ef",
"type": "ui_tab",
"name": "Clients",
"icon": "",
"disabled": false,
"hidden": false
},
{
"id": "5850cb65c596909b",
"type": "tls-config",
"name": "schlag config",
"cert": "",
"key": "",
"ca": "",
"certname": "",
"keyname": "",
"caname": "",
"servername": "",
"verifyservercert": false,
"alpnprotocol": ""
},
{
"id": "ceab5cf497e7e421",
"type": "tls-config",
"name": "shlag config",
"cert": "",
"key": "",
"ca": "",
"certname": "",
"keyname": "",
"caname": "",
"servername": "",
"verifyservercert": false,
"alpnprotocol": ""
},
{
"id": "b0f715d01c382afe",
"type": "mqtt in",
"z": "27ca1ab3d111d118",
"name": "mqtt",
"topic": "+",
"qos": "2",
"datatype": "auto-detect",
"broker": "2282c53e6f2d220c",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 90,
"y": 220,
"wires": [
[
"2a070a302599348a"
]
]
},
{
"id": "0f6571cbd5a08e12",
"type": "function",
"z": "27ca1ab3d111d118",
"name": "store status",
"func": "// for now => has a payload = connected\nconst isConnected = Boolean(msg.payload);\nconst map = flow.get('clients');\nconst client = {\n description: msg.payload.identification.id,\n title: msg.payload.idShort,\n isConnected: isConnected\n};\n\nmap.set(msg.payload.identification.id, client);\nmsg.payload = map;\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "// Code added here will be run once\n// whenever the node is started.\nflow.set('clients', new Map());",
"finalize": "",
"libs": [],
"x": 430,
"y": 220,
"wires": [
[
"1d11aac3329ba98d"
]
]
},
{
"id": "2a070a302599348a",
"type": "switch",
"z": "27ca1ab3d111d118",
"name": "model type",
"property": "payload.modelType.name",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "AssetAdministrationShell",
"vt": "str"
},
{
"t": "eq",
"v": "Submodel",
"vt": "str"
},
{
"t": "else"
}
],
"checkall": "false",
"repair": false,
"outputs": 3,
"x": 250,
"y": 220,
"wires": [
[
"0f6571cbd5a08e12",
"356d262113f2172e"
],
[
"c6f4da7bfcc9ee69"
],
[
"37acdbd7d61f880a"
]
]
},
{
"id": "1d11aac3329ba98d",
"type": "function",
"z": "27ca1ab3d111d118",
"name": "retrieve connected",
"func": "msg.payload = [...msg.payload]\n .filter(([_, value]) => value.isConnected)\n .map(([_, value]) => value);\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 610,
"y": 220,
"wires": [
[
"36db99b4430e55d1"
]
]
},
{
"id": "36db99b4430e55d1",
"type": "ui_list",
"z": "27ca1ab3d111d118",
"group": "316f43488033c495",
"name": "list",
"order": 1,
"width": "8",
"height": "10",
"lineType": "three",
"actionType": "click",
"allowHTML": false,
"outputs": 1,
"topic": "",
"x": 790,
"y": 220,
"wires": [
[
"f1662dd7df4e450c"
]
]
},
{
"id": "f1662dd7df4e450c",
"type": "link out",
"z": "27ca1ab3d111d118",
"name": "link out - clicked asset",
"mode": "link",
"links": [
"8729880c79bd594e"
],
"x": 875,
"y": 220,
"wires": []
},
{
"id": "356d262113f2172e",
"type": "function",
"z": "27ca1ab3d111d118",
"name": "asset → submodels",
"func": "/** @type {Map<string, string[]>} */\nconst map = global.get('submodelMap');\nconst submodels = msg.payload.submodels.flatMap(obj =>\n obj.keys.map(key => key.value)\n);\n\nmap.set(msg.payload.identification.id, submodels);",
"outputs": 0,
"noerr": 0,
"initialize": "// Code added here will be run once\n// whenever the node is started.\nglobal.set('submodelMap', new Map());",
"finalize": "",
"libs": [],
"x": 470,
"y": 180,
"wires": []
},
{
"id": "c6f4da7bfcc9ee69",
"type": "function",
"z": "27ca1ab3d111d118",
"name": "store submodel",
"func": "const map = global.get('submodels');\nmap.set(msg.payload.identification.id, msg.payload);\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "// Code added here will be run once\n// whenever the node is started.\nglobal.set('submodels', new Map());",
"finalize": "",
"libs": [],
"x": 460,
"y": 260,
"wires": [
[
"e69ab0ee6ab78025"
]
]
},
{
"id": "21862df7667fcb11",
"type": "inject",
"z": "27ca1ab3d111d118",
"name": "reset",
"props": [
{
"p": "payload"
}
],
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": "0",
"topic": "",
"payload": "[]",
"payloadType": "json",
"x": 650,
"y": 180,
"wires": [
[
"36db99b4430e55d1"
]
]
},
{
"id": "dd5f965e.fb70b8",
"type": "ui_template",
"z": "27ca1ab3d111d118",
"group": "",
"name": "css slsmkfùmzoqf",
"order": 4,
"width": 0,
"height": 0,
"format": "<style>\n .ce-block__content {\n max-width: none !important;\n margin: 0 1% !important;\n }\n\n p.nr-dashboard-cardtitle {\n text-decoration: underline;\n }\n\n .ce-block__content h1 {\n font-size: none !important;\n }\n\n .popup {\n padding: 10px !important;\n }\n\n ui-card-panel {\n padding: 10px !important;\n }\n\n</style>",
"storeOutMessages": true,
"fwdInMessages": true,
"resendOnRefresh": false,
"templateScope": "global",
"className": "",
"x": 630,
"y": 80,
"wires": [
[] []
]
},
{
"id": "325dffad2dd74522",
"type": "function",
"z": "27ca1ab3d111d118",
"name": "concept description",
"func": "/** @type {Map<string, any>} */\nconst concepts = global.get('concepts');\n\nmsg.payload.forEach(concept => {\n const id = concept.identification.id;\n concepts.set(id, concept);\n})",
"outputs": 0,
"noerr": 0,
"initialize": "// Code added here will be run once\n// whenever the node is started.\nglobal.set('concepts', new Map());",
"finalize": "",
"libs": [],
"x": 610,
"y": 300,
"wires": []
},
{
"id": "37acdbd7d61f880a",
"type": "switch",
"z": "27ca1ab3d111d118",
"name": "concept filter",
"property": "topic",
"propertyType": "msg",
"rules": [
{
"t": "regex",
"v": "concept.*descriptions?.*",
"vt": "str",
"case": true
}
],
"checkall": "true",
"repair": false,
"outputs": 1,
"x": 430,
"y": 300,
"wires": [
[
"325dffad2dd74522"
]
]
},
{
"id": "63318fe2d16dfbd0",
"type": "function",
"z": "27ca1ab3d111d118",
"name": "store capabilities",
"func": "const capabilities = global.get('capabilities');\nconst subcaps = msg.payload.submodelElements\n .filter(element =>\n element.modelType.name === 'RelationshipElement'\n )\n\nsubcaps.forEach(element =>\n capabilities.set(\n element.first.keys.at(1).value, \n element.second.keys.at(0).value\n )\n);\n\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "// Code added here will be run once\n// whenever the node is started.\nglobal.set('capabilities', new Map());",
"finalize": "",
"libs": [],
"x": 790,
"y": 260,
"wires": [
[
"f92afa1f37cc46cb"
]
]
},
{
"id": "e69ab0ee6ab78025",
"type": "switch",
"z": "27ca1ab3d111d118",
"name": "cap filter",
"property": "payload.idShort",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "Capabilities",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 1,
"x": 620,
"y": 260,
"wires": [
[
"63318fe2d16dfbd0"
]
]
},
{
"id": "9ace58fe9a8ef6eb",
"type": "inject",
"z": "27ca1ab3d111d118",
"name": "",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": "0.5",
"topic": "",
"payload": "Home",
"payloadType": "str",
"x": 110,
"y": 80,
"wires": [
[
"089217f817d51501"
]
]
},
{
"id": "e8ece81e1163d14a",
"type": "ui_ui_control",
"z": "27ca1ab3d111d118",
"name": "",
"events": "all",
"x": 420,
"y": 80,
"wires": [
[]
]
},
{
"id": "0f773f94330e38ae",
"type": "ui_button",
"z": "27ca1ab3d111d118",
"name": "",
"group": "056d3115f1f3b8b2",
"order": 2,
"width": 0,
"height": 0,
"passthru": false,
"label": "Clients",
"tooltip": "",
"color": "",
"bgcolor": "",
"className": "",
"icon": "",
"payload": "Clients",
"payloadType": "str",
"topic": "topic",
"topicType": "msg",
"x": 270,
"y": 40,
"wires": [
[
"e8ece81e1163d14a"
]
]
},
{
"id": "58e1536359af4b69",
"type": "ui_button",
"z": "27ca1ab3d111d118",
"name": "",
"group": "056d3115f1f3b8b2",
"order": 3,
"width": 0,
"height": 0,
"passthru": false,
"label": "Workpiece order",
"tooltip": "",
"color": "",
"bgcolor": "",
"className": "",
"icon": "",
"payload": "Workpiece order",
"payloadType": "str",
"topic": "topic",
"topicType": "msg",
"x": 240,
"y": 120,
"wires": [
[
"e8ece81e1163d14a"
]
]
},
{
"id": "089217f817d51501",
"type": "ui_button",
"z": "27ca1ab3d111d118",
"name": "",
"group": "316f43488033c495",
"order": 2,
"width": 0,
"height": 0,
"passthru": true,
"label": "Back home",
"tooltip": "",
"color": "",
"bgcolor": "",
"className": "",
"icon": "",
"payload": "Home",
"payloadType": "str",
"topic": "topic",
"topicType": "msg",
"x": 250,
"y": 80,
"wires": [
[
"e8ece81e1163d14a"
]
]
},
{
"id": "f92afa1f37cc46cb",
"type": "link out",
"z": "27ca1ab3d111d118",
"name": "dmdfsfkodmdfkg",
"mode": "link",
"links": [
"b8640315f79bbc2c",
"58be501a101c8482"
],
"x": 915,
"y": 260,
"wires": []
},
{
"id": "8729880c79bd594e",
"type": "link in",
"z": "593bb738e7507707",
"name": "link in 1",
"links": [
"f1662dd7df4e450c",
"c9bfe0162fe24c52"
],
"x": 85,
"y": 160,
"wires": [
[
"689f243db86e15b3"
]
]
},
{
"id": "0d77bbe26c501f2a",
"type": "inject",
"z": "593bb738e7507707",
"name": "reset",
"props": [
{
"p": "payload"
}
],
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": "0",
"topic": "",
"payload": "[{\"title\": \"Select a client\"}]",
"payloadType": "json",
"x": 250,
"y": 80,
"wires": [
[
"bf4ce6760659e9da"
]
]
},
{
"id": "bf4ce6760659e9da",
"type": "ui_list",
"z": "593bb738e7507707",
"group": "80a80175907e2ec4",
"name": "",
"order": 1,
"width": "8",
"height": "10",
"lineType": "three",
"actionType": "click",
"allowHTML": false,
"outputs": 1,
"topic": "",
"x": 430,
"y": 160,
"wires": [
[
"ef433e7595d5c4f2"
]
]
},
{
"id": "689f243db86e15b3",
"type": "function",
"z": "593bb738e7507707",
"name": "list from submodel",
"func": "/** @type {Map<string, any>} */\nconst submodels = global.get('submodels');\n\n// extracts the capabilities submodel and retrieve\n// the submodels associated with a relationship element,\n// building an array of object for the list node\nmsg.payload = global.get('submodelMap')\n .get(msg.payload.description)\n .map(id => submodels.get(id))\n .find(submodel => submodel.idShort === 'Capabilities')\n .submodelElements\n .filter(element =>\n element.modelType.name === 'RelationshipElement'\n )\n .map(element => ({\n title: element.first.keys.at(1).value,\n description: element.second.keys.at(0).value\n }));\n\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 210,
"y": 160,
"wires": [
[
"bf4ce6760659e9da",
"8d7f127f6e8b4203"
]
]
},
{
"id": "a28b244bb8e51bc4",
"type": "ui_ui_control",
"z": "593bb738e7507707",
"name": "",
"events": "change",
"x": 640,
"y": 120,
"wires": [
[]
]
},
{
"id": "8d7f127f6e8b4203",
"type": "change",
"z": "593bb738e7507707",
"name": "change to caps.",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "Capabilities",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 460,
"y": 120,
"wires": [
[
"a28b244bb8e51bc4"
]
]
},
{
"id": "a594eb612218b2e3",
"type": "ui_button",
"z": "593bb738e7507707",
"name": "",
"group": "80a80175907e2ec4",
"order": 1,
"width": 0,
"height": 0,
"passthru": false,
"label": "Back to list",
"tooltip": "",
"color": "",
"bgcolor": "",
"className": "",
"icon": "arrow_back",
"payload": "",
"payloadType": "str",
"topic": "topic",
"topicType": "msg",
"x": 230,
"y": 120,
"wires": [
[
"d2c70a9d17d17501",
"bf4ce6760659e9da"
]
]
},
{
"id": "d2c70a9d17d17501",
"type": "change",
"z": "593bb738e7507707",
"name": "change to home",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "Clients",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 460,
"y": 80,
"wires": [
[
"a28b244bb8e51bc4"
]
]
},
{
"id": "b91eb42511d8b336",
"type": "catch",
"z": "593bb738e7507707",
"name": "",
"scope": [
"689f243db86e15b3"
],
"uncaught": false,
"x": 110,
"y": 200,
"wires": [
[
"ef0e0e5a4eeaad5a"
]
]
},
{
"id": "ac9f9fa8573bdbeb",
"type": "ui_toast",
"z": "593bb738e7507707",
"position": "dialog",
"displayTime": "3",
"highlight": "",
"sendall": false,
"outputs": 1,
"ok": "OK",
"cancel": "",
"raw": true,
"className": "popup",
"topic": "Error",
"name": "",
"x": 410,
"y": 200,
"wires": [
[]
]
},
{
"id": "ef0e0e5a4eeaad5a",
"type": "change",
"z": "593bb738e7507707",
"name": "dialog text",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "Could not retrieve the capabilities of the asset.<br>Make sure this asset shares a \"Capabilities\" submodel containing its functionalities.",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 250,
"y": 200,
"wires": [
[
"ac9f9fa8573bdbeb"
]
]
},
{
"id": "ef433e7595d5c4f2",
"type": "function",
"z": "593bb738e7507707",
"name": "formatting",
"func": "const submodel = global.get('submodels').get(msg.payload.description);\n\n/** @type {{time: number;blocks: {id: string;type: string;data: {text: any;level: number;};}[];version: string;}} */\nconst content = {\n time: new Date().getTime(),\n blocks: [\n {\n id: \"header\",\n type: \"header\",\n data: {\n text: `<u class=\"cdx-underline\">${msg.payload.title}</u>`,\n level: 1\n },\n },\n ],\n version: \"2.26.5\"\n}\n\nmsg.payload = content;\nmsg.topic = \"render\";\nmsg.submodel = submodel;\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "// Code added here will be run once\n// whenever the node is started.\nflow.set('clicked', undefined)",
"finalize": "",
"libs": [],
"x": 560,
"y": 160,
"wires": [
[
"1e55e4a8898e2f68"
]
]
},
{
"id": "ac616b75994208a7",
"type": "inject",
"z": "593bb738e7507707",
"name": "reset",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": "0",
"topic": "render",
"payload": "{\"blocks\":[]}",
"payloadType": "json",
"x": 570,
"y": 200,
"wires": [
[
"dc020b3060cb7c2a"
]
]
},
{
"id": "1e55e4a8898e2f68",
"type": "function",
"z": "593bb738e7507707",
"name": "editor message",
"func": "const collection = /SubmodelElement(Collection|List)/g;\nconst tab = level => \"ㅤㅤ\".repeat(level - 2);\n\n/**\n * Transform PascalCase text into a normal sentence\n */\nconst niceText = text =>\n text.replaceAll(/(?<=.)[A-Z]/g, match =>\n ` ${match.toLocaleLowerCase()}`\n );\n\n/**\n * Returns an Editor.js paragraph block for a\n * submodel element\n */\nconst valueBlock = (element, level) => ({\n id: crypto.randomUUID(),\n type: \"paragraph\",\n data: {\n text: `${tab(level - 1)}${niceText(element.idShort)}: ${global.get('text')(element)}`\n }\n});\n\n/**\n * Returns an Editor.js header block for\n * a submodel element\n */\nconst headerBlock = (element, level) => ({\n id: crypto.randomUUID(),\n type: \"header\",\n data: {\n text: `${tab(level)}${niceText(element.idShort)}`,\n level: Math.min(level, 6)\n }\n});\n\n/**\n * Returns an Editor.js blank paragraph block\n */\nconst blankBlock = {\n id: crypto.randomUUID(),\n type: \"paragraph\",\n data: {\n text: \" \"\n }\n};\n\nconst table = msg.payload.blocks;\n\n/**\n * Function that stores Editor.js-compatible objects\n * into ann array, in order to display\n * information about a submodel.\n * Indents blocks for better visibility.\n * @param {[]} elements SubmodelElements fields of a Submodel\n * @param {number} level the level of indentation of the blocks\n * @param {[]} arr an array to be filled with the blocks\n */\nconst better = (elements, level, arr) => {\n elements.forEach(element => {\n if (element.modelType.name.match(collection)) {\n // if (!element.value.every(e => e.category.toLocaleLowerCase() === \"variable\")) {\n arr.push(headerBlock(element, level));\n better(element.value, level + 1, arr);\n arr.push(blankBlock);\n // }\n } else /** if (element.category.toLocaleLowerCase() !== \"variable\") */ {\n arr.push(valueBlock(element, level));\n }\n });\n};\n// -> uncomment to filter out variables\n\nbetter(msg.submodel.submodelElements, 2, table);\nmsg.payload.blocks = table;\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "// Code added here will be run once\n// whenever the node is started.\nglobal.set(\"text\", element => {\n if (element.value === \"\") {\n return \"no information\"\n }\n\n const getUnit = element => {\n try {\n const conceptId = element.semanticId.keys.at(0).value;\n const concept = global.get('concepts').get(conceptId);\n return concept.embeddedDataSpecifications.at(0).dataSpecificationContent.unit;\n } catch (error) {\n return \"\";\n }\n }\n\n const richText = element => {\n const type = element.valueType.dataObjectType.name;\n if (type.toLocaleLowerCase() === \"boolean\" && element.value.toLocaleLowerCase() === \"no\") {\n return `Not ${element.idShort.toLocaleLowerCase()}`;\n } else if (type.toLocaleLowerCase() === \"boolean\" && element.value.toLocaleLowerCase() === \"yes\") {\n return `${element.idShort}`;\n } else {\n return element.value\n }\n }\n\n let res = \"\";\n\n switch (element.modelType.name.toLocaleLowerCase()) {\n case \"property\":\n res += richText(element);\n break;\n\n case \"multilanguageproperty\":\n res += `${element.value}`;\n break;\n\n case \"range\":\n res += `from ${element.min} to ${element.max}`;\n break;\n\n case \"file\":\n res += `${element.mimeType.split(\"/\")[1]} file (${element.value})`;\n break;\n\n default:\n res += `idk`;\n break;\n }\n\n return `${res} ${getUnit(element)}`\n});",
"finalize": "",
"libs": [
{
"var": "crypto",
"module": "crypto"
}
],
"x": 720,
"y": 160,
"wires": [
[
"13dd2a0c6fc2cccd"
]
]
},
{
"id": "dc020b3060cb7c2a",
"type": "ui_button",
"z": "593bb738e7507707",
"name": "",
"group": "f46a108f2a7fd47d",
"order": 2,
"width": "16",
"height": "1",
"passthru": true,
"label": "Clear",
"tooltip": "",
"color": "",
"bgcolor": "",
"className": "",
"icon": "",
"payload": "",
"payloadType": "str",
"topic": "render",
"topicType": "str",
"x": 750,
"y": 200,
"wires": [
[
"20662e50b107246b",
"13dd2a0c6fc2cccd"
]
]
},
{
"id": "20662e50b107246b",
"type": "change",
"z": "593bb738e7507707",
"name": "",
"rules": [
{
"t": "set",
"p": "clicked",
"pt": "flow",
"to": "null",
"tot": "json"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 920,
"y": 200,
"wires": [
[]
]
},
{
"id": "13dd2a0c6fc2cccd",
"type": "ui_editor",
"z": "593bb738e7507707",
"group": "f46a108f2a7fd47d",
"order": 1,
"width": "16",
"height": "10",
"name": "",
"readonly": true,
"monitorUpdate": false,
"outputs": 1,
"x": 890,
"y": 160,
"wires": [
[]
]
},
{
"id": "a81b3b9b740bc85f",
"type": "inject",
"z": "2bc19b2f7b518cb2",
"name": "base stuff",
"props": [
{
"p": "payload"
}
],
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": "0.1",
"topic": "",
"payload": "[{\"Cutting\":{\"capability\":\"Cutting\",\"submodels\":[]}},{\"Engraving\":{\"capability\":\"Engraving\",\"submodels\":[]}},{\"Painting\":{\"capability\":\"Painting\",\"submodels\":[]}}]",
"payloadType": "json",
"x": 280,
"y": 80,
"wires": [
[
"b17f15ef905a8689"
]
]
},
{
"id": "b17f15ef905a8689",
"type": "function",
"z": "2bc19b2f7b518cb2",
"name": "fill dropdown",
"func": "/** @type {Map<string, string>} */\nconst capabilities = global.get('capabilities');\n// capabilities.set('Bending', 'url');\nconst items = msg.payload;\n\n// with the base dropdown config we have :\n// -> add submodels to capabilities already here\n// -> add cap+submodel if it's not\ncapabilities.forEach((value, key) => {\n const idx = items.findIndex(obj => obj[key]?.submodels.length === 0);\n if (idx >= 0) {\n items[idx][key].submodels.push(value);\n } else {\n const obj = {};\n obj[key] = {\n capability: key,\n submodels: [value]\n };\n items.push(obj);\n }\n});\n\nflow.set('registeredCapabilities', items);\nmsg.options = items;\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "// Code added here will be run once\n// whenever the node is started.\nflow.set('registeredCapabilities', []);",
"finalize": "",
"libs": [],
"x": 450,
"y": 80,
"wires": [
[
"fd5ce40b493557db"
]
]
},
{
"id": "97386f3e3179aa1b",
"type": "change",
"z": "2bc19b2f7b518cb2",
"name": "",
"rules": [
{
"t": "set",
"p": "selected",
"pt": "flow",
"to": "payload",
"tot": "msg"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 780,
"y": 80,
"wires": [
[]
]
},
{
"id": "6656b321ad96cfa2",
"type": "inject",
"z": "2bc19b2f7b518cb2",
"name": "other stuff",
"props": [
{
"p": "options",
"v": "[\"Wood\",\"Plastic\",\"Metal\", \"Acrylic\"]",
"vt": "json"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": 0.1,
"topic": "",
"x": 270,
"y": 120,
"wires": [
[
"3f175d56e52394c5"
]
]
},
{
"id": "aff2658dc26c28e8",
"type": "change",
"z": "2bc19b2f7b518cb2",
"name": "",
"rules": [
{
"t": "set",
"p": "workablematerial",
"pt": "flow",
"to": "payload",
"tot": "msg"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 650,
"y": 120,
"wires": [
[]
]
},
{
"id": "08fd977d41ee497c",
"type": "function",
"z": "2bc19b2f7b518cb2",
"name": "payload factory",
"func": "const canBeNothing = /registeredCapabilities|colour/g\n\nflow.keys().forEach(key => {\n if (key.match(canBeNothing)) return;\n const value = flow.get(key);\n if (!value || value.length === 0) {\n throw Error();\n }\n msg.payload[key] = value;\n});\n\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 400,
"y": 420,
"wires": [
[
"dc4a14cbb5fee37f",
"7a07356f3fce36ae"
]
]
},
{
"id": "02bdca349f0277af",
"type": "function",
"z": "2bc19b2f7b518cb2",
"name": "store in flow idk",
"func": "const number = Number(msg.payload);\nflow.set(msg.topic, number);\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 640,
"y": 200,
"wires": [
[]
]
},
{
"id": "80725051792ea031",
"type": "inject",
"z": "2bc19b2f7b518cb2",
"name": "",
"props": [
{
"p": "payload"
}
],
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "str",
"x": 290,
"y": 200,
"wires": [
[
"e3d8b7d3acb18df8",
"373b1ad758e116ca",
"4ec9cd6fe1155089"
]
]
},
{
"id": "dc4a14cbb5fee37f",
"type": "debug",
"z": "2bc19b2f7b518cb2",
"name": "debug 1",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "msg",
"statusVal": "",
"statusType": "auto",
"x": 580,
"y": 400,
"wires": []
},
{
"id": "612fd715cb7e599d",
"type": "catch",
"z": "2bc19b2f7b518cb2",
"name": "",
"scope": [
"08fd977d41ee497c"
],
"uncaught": false,
"x": 230,
"y": 460,
"wires": [
[
"322a84b449820b68"
]
]
},
{
"id": "322a84b449820b68",
"type": "change",
"z": "2bc19b2f7b518cb2",
"name": "fill err",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "fill everything :)",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 370,
"y": 460,
"wires": [
[
"cbcd197b7e536209"
]
]
},
{
"id": "cbcd197b7e536209",
"type": "ui_toast",
"z": "2bc19b2f7b518cb2",
"position": "dialog",
"displayTime": "3",
"highlight": "",
"sendall": true,
"outputs": 1,
"ok": "OK",
"cancel": "",
"raw": false,
"className": "popup",
"topic": "",
"name": "",
"x": 550,
"y": 460,
"wires": [
[]
]
},
{
"id": "fd5ce40b493557db",
"type": "ui_dropdown",
"z": "2bc19b2f7b518cb2",
"name": "capabilities",
"label": "",
"tooltip": "",
"place": "Select option*",
"group": "f42eda3bec77a0ec",
"order": 1,
"width": 6,
"height": 1,
"passthru": false,
"multiple": true,
"options": [
{
"label": "",
"value": "",
"type": "str"
}
],
"payload": "",
"topic": "topic",
"topicType": "msg",
"className": "",
"x": 610,
"y": 80,
"wires": [
[
"97386f3e3179aa1b"
]
]
},
{
"id": "e3d8b7d3acb18df8",
"type": "ui_text_input",
"z": "2bc19b2f7b518cb2",
"name": "length",
"label": "Length (mm)*",
"tooltip": "",
"group": "f42eda3bec77a0ec",
"order": 4,
"width": 4,
"height": 1,
"passthru": true,
"mode": "number",
"delay": "10",
"topic": "length",
"sendOnBlur": true,
"className": "",
"topicType": "str",
"x": 430,
"y": 160,
"wires": [
[
"02bdca349f0277af"
]
]
},
{
"id": "373b1ad758e116ca",
"type": "ui_text_input",
"z": "2bc19b2f7b518cb2",
"name": "width",
"label": "Width (mm)*",
"tooltip": "",
"group": "f42eda3bec77a0ec",
"order": 5,
"width": 4,
"height": 1,
"passthru": true,
"mode": "number",
"delay": "10",
"topic": "width",
"sendOnBlur": false,
"className": "",
"topicType": "str",
"x": 430,
"y": 200,
"wires": [
[
"02bdca349f0277af"
]
]
},
{
"id": "4ec9cd6fe1155089",
"type": "ui_text_input",
"z": "2bc19b2f7b518cb2",
"name": "thickness",
"label": "Thickness (mm)*",
"tooltip": "",
"group": "f42eda3bec77a0ec",
"order": 6,
"width": 4,
"height": 1,
"passthru": true,
"mode": "number",
"delay": "10",
"topic": "thickness",
"sendOnBlur": false,
"className": "",
"topicType": "str",
"x": 440,
"y": 240,
"wires": [
[
"02bdca349f0277af"
]
]
},
{
"id": "3f175d56e52394c5",
"type": "ui_dropdown",
"z": "2bc19b2f7b518cb2",
"name": "materials",
"label": "",
"tooltip": "",
"place": "Select material*",
"group": "f42eda3bec77a0ec",
"order": 2,
"width": 6,
"height": 1,
"passthru": true,
"multiple": false,
"options": [
{
"label": "",
"value": "",
"type": "str"
}
],
"payload": "",
"topic": "topic",
"topicType": "msg",
"className": "",
"x": 440,
"y": 120,
"wires": [
[
"aff2658dc26c28e8"
]
]
},
{
"id": "be52a6ec742aae62",
"type": "ui_button",
"z": "2bc19b2f7b518cb2",
"name": "",
"group": "f42eda3bec77a0ec",
"order": 7,
"width": 0,
"height": 0,
"passthru": false,
"label": "submit",
"tooltip": "",
"color": "",
"bgcolor": "",
"className": "",
"icon": "",
"payload": "{}",
"payloadType": "json",
"topic": "topic",
"topicType": "msg",
"x": 230,
"y": 420,
"wires": [
[
"08fd977d41ee497c"
]
]
},
{
"id": "7a07356f3fce36ae",
"type": "link out",
"z": "2bc19b2f7b518cb2",
"name": "link out 1",
"mode": "link",
"links": [
"2a48607dce78b96a",
"cc23bdf032d1e4c5"
],
"x": 835,
"y": 420,
"wires": []
},
{
"id": "cc936221d2a30b89",
"type": "ui_list",
"z": "2bc19b2f7b518cb2",
"group": "1bea595dc9db51b7",
"name": "",
"order": 1,
"width": 0,
"height": 0,
"lineType": "two",
"actionType": "click",
"allowHTML": false,
"outputs": 1,
"topic": "",
"x": 530,
"y": 500,
"wires": [
[
"8b014741fffd6f93",
"15dd31c7abeb942a"
]
]
},
{
"id": "6b8e2ad1c05cb496",
"type": "inject",
"z": "2bc19b2f7b518cb2",
"name": "",
"props": [
{
"p": "payload"
}
],
"repeat": "5",
"crontab": "",
"once": true,
"onceDelay": "0.5",
"topic": "",
"payload": "[{\"title\":\"E12 Room Plaque\",\"description\":\"Piece of wood engraved with \\\"E12\\\"\",\"workpiece\":{\"length\":120,\"width\":120,\"thickness\":10,\"selected\":[{\"capability\":\"Engraving\",\"submodels\":[]}],\"workablematerial\":\"Wood\"}},{\"title\":\"Protective piece of plastic\",\"description\":\"Plastic piece that protects from lasers\",\"workpiece\":{\"length\":200,\"width\":80,\"thickness\":5,\"selected\":[{\"capability\":\"Cutting\",\"submodels\":[]},{\"capability\":\"Engraving\",\"submodels\":[]}],\"workablematerial\":\"Acrylic\"}},{\"title\":\"Painted piece of metal\",\"description\":\"Piece of metal with red paint after some engraving\",\"workpiece\":{\"length\":12,\"width\":20,\"thickness\":60,\"colour\":\"Red\",\"selected\":[{\"capability\":\"Engraving\",\"submodels\":[]},{\"capability\":\"Painting\",\"submodels\":[]}],\"workablematerial\":\"Metal\"}}]",
"payloadType": "json",
"x": 230,
"y": 500,
"wires": [
[
"95da606fa064c3bb"
]
]
},
{
"id": "95da606fa064c3bb",
"type": "function",
"z": "2bc19b2f7b518cb2",
"name": "fill the list",
"func": "const stuff = flow.get('registeredCapabilities');\n\nmsg.payload.forEach(obj => {\n obj.workpiece.selected.forEach(hm =>\n hm.submodels = stuff.find(\n cap => cap[hm.capability]\n )[hm.capability].submodels\n )\n});\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 380,
"y": 500,
"wires": [
[
"cc936221d2a30b89"
]
]
},
{
"id": "8b014741fffd6f93",
"type": "change",
"z": "2bc19b2f7b518cb2",
"name": "",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "payload.workpiece",
"tot": "msg"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 700,
"y": 500,
"wires": [
[
"7a07356f3fce36ae"
]
]
},
{
"id": "811b39730262f4c3",
"type": "inject",
"z": "2bc19b2f7b518cb2",
"name": "colour list!",
"props": [
{
"p": "options",
"v": "[\"Red\",\"Yellow\",\"Turquoise\",\"No colour\"]",
"vt": "json"
}
],
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": 0.1,
"topic": "",
"x": 290,
"y": 280,
"wires": [
[
"e73e2445b47c515c"
]
]
},
{
"id": "e73e2445b47c515c",
"type": "ui_dropdown",
"z": "2bc19b2f7b518cb2",
"name": "colours",
"label": "",
"tooltip": "",
"place": "Select a colour",
"group": "f42eda3bec77a0ec",
"order": 3,
"width": 12,
"height": 1,
"passthru": false,
"multiple": false,
"options": [
{
"label": "",
"value": "",
"type": "str"
}
],
"payload": "",
"topic": "topic",
"topicType": "msg",
"className": "",
"x": 440,
"y": 280,
"wires": [
[
"3c78dd5bac3ccc2b"
]
]
},
{
"id": "3c78dd5bac3ccc2b",
"type": "change",
"z": "2bc19b2f7b518cb2",
"name": "",
"rules": [
{
"t": "set",
"p": "colour",
"pt": "flow",
"to": "payload",
"tot": "msg"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 620,
"y": 280,
"wires": [
[]
]
},
{
"id": "b8640315f79bbc2c",
"type": "link in",
"z": "2bc19b2f7b518cb2",
"name": "link in 8",
"links": [
"f92afa1f37cc46cb"
],
"x": 145,
"y": 40,
"wires": [
[
"3429169128e30ca3"
]
]
},
{
"id": "3429169128e30ca3",
"type": "change",
"z": "2bc19b2f7b518cb2",
"name": "",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "[{\"Cutting\":{\"capability\":\"Cutting\",\"submodels\":[]}},{\"Engraving\":{\"capability\":\"Engraving\",\"submodels\":[]}},{\"Painting\":{\"capability\":\"Painting\",\"submodels\":[]}}]",
"tot": "json"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 260,
"y": 40,
"wires": [
[
"b17f15ef905a8689"
]
]
},
{
"id": "97777a9dd42807be",
"type": "debug",
"z": "2bc19b2f7b518cb2",
"name": "debug 5",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "false",
"statusVal": "",
"statusType": "auto",
"x": 680,
"y": 540,
"wires": []
},
{
"id": "15dd31c7abeb942a",
"type": "debug",
"z": "2bc19b2f7b518cb2",
"name": "debug 5",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "false",
"statusVal": "",
"statusType": "auto",
"x": 680,
"y": 540,
"wires": []
},
{
"id": "58be501a101c8482",
"type": "link in",
"z": "2bc19b2f7b518cb2",
"name": "link in 9",
"links": [
"f92afa1f37cc46cb"
],
"x": 85,
"y": 540,
"wires": [
[
"027f7b9e6c21d994"
]
]
},
{
"id": "027f7b9e6c21d994",
"type": "change",
"z": "2bc19b2f7b518cb2",
"name": "",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "[{\"title\":\"E12 Room Plaque\",\"description\":\"Piece of wood engraved with \\\"E12\\\"\",\"workpiece\":{\"length\":120,\"width\":120,\"thickness\":10,\"selected\":[{\"capability\":\"Engraving\",\"submodels\":[]}],\"workablematerial\":\"Wood\"}},{\"title\":\"Protective piece of plastic\",\"description\":\"Plastic piece that protects from lasers\",\"workpiece\":{\"length\":200,\"width\":80,\"thickness\":5,\"selected\":[{\"capability\":\"Cutting\",\"submodels\":[]},{\"capability\":\"Engraving\",\"submodels\":[]}],\"workablematerial\":\"Acrylic\"}},{\"title\":\"Painted piece of metal\",\"description\":\"Piece of metal with red paint after some engraving\",\"workpiece\":{\"length\":12,\"width\":20,\"thickness\":60,\"colour\":\"Red\",\"selected\":[{\"capability\":\"Engraving\",\"submodels\":[]},{\"capability\":\"Painting\",\"submodels\":[]}],\"workablematerial\":\"Metal\"}}]",
"tot": "json"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 200,
"y": 540,
"wires": [
[
"95da606fa064c3bb"
]
]
},
{
"id": "2a48607dce78b96a",
"type": "link in",
"z": "f96e455ab747ba2b",
"name": "link in 5",
"links": [
"7a07356f3fce36ae"
],
"x": 55,
"y": 80,
"wires": [
[
"61434116aba62c5e"
]
]
},
{
"id": "61434116aba62c5e",
"type": "function",
"z": "f96e455ab747ba2b",
"name": "available filter",
"func": "const available = [], unavailable = [];\n\nmsg.payload.selected.forEach(wantedCapacity => {\n if (wantedCapacity.submodels.length > 0) {\n available.push(wantedCapacity);\n } else {\n unavailable.push(wantedCapacity);\n }\n});\n\ndelete msg.payload.selected;\nmsg.available = available;\nmsg.unavailable = unavailable;\nmsg.baseInput = msg.payload;\n\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 180,
"y": 80,
"wires": [
[
"8e4eaf8f3761dd09"
]
]
},
{
"id": "b8399d7f9cf6bf2c",
"type": "function",
"z": "f96e455ab747ba2b",
"name": "find an element",
"func": "const coll = /SubmodelElement(Collection|List)/g;\nconst submodels = global.get('submodels');\n\n/**\n * Allows to find a specific element with provided\n * id within a SubmodelElement.\n */\nconst findElement = (elements, id) => {\n for(const element of elements) {\n if (element.idShort.toLocaleLowerCase() === id.toLocaleLowerCase()) {\n return element;\n }\n if (element.modelType.name.match(coll)) {\n const find = findElement(element.value, id);\n if (find) return find;\n }\n }\n}\n\n// keep originally entered value for later comparision\nconst enteredValue = msg.payload;\nmsg.payload = [];\n\n// look through available capabilities to map them\nmsg.available.forEach(available => {\n const mapped = available.submodels.map(submodel => {\n const find = findElement(\n submodels.get(submodel).submodelElements,\n msg.key\n );\n if (find) find.enteredValue = enteredValue;\n return find;\n });\n if (mapped.every(obj => obj)) {\n available.submodels = mapped;\n msg.payload.push(available);\n }\n});\n\nnode.warn(msg);\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 400,
"y": 140,
"wires": [
[
"c1ef5b072db03648"
]
]
},
{
"id": "8e4eaf8f3761dd09",
"type": "split",
"z": "f96e455ab747ba2b",
"name": "",
"splt": "\\n",
"spltType": "str",
"arraySplt": 1,
"arraySpltType": "len",
"stream": false,
"addname": "key",
"x": 330,
"y": 80,
"wires": [
[
"b8399d7f9cf6bf2c"
]
]
},
{
"id": "cb2883b1acc66248",
"type": "join",
"z": "f96e455ab747ba2b",
"name": "",
"mode": "auto",
"build": "object",
"property": "payload",
"propertyType": "msg",
"key": "topic",
"joiner": "\\n",
"joinerType": "str",
"accumulate": true,
"timeout": "",
"count": "",
"reduceRight": false,
"reduceExp": "",
"reduceInit": "",
"reduceInitType": "",
"reduceFixup": "",
"x": 570,
"y": 200,
"wires": [
[
"cbb098a2c48230a6"
]
]
},
{
"id": "c1ef5b072db03648",
"type": "function",
"z": "f96e455ab747ba2b",
"name": "check requirements",
"func": "/**\n * Check whether the value entered by the client is\n * acceptable depending on the model type of the submodel\n */\nconst checkValue = submodel => {\n const type = submodel.modelType?.name;\n const enteredValue = submodel.enteredValue;\n\n if (type.match(/SubmodelElement(Collection|List)/g)) {\n return Boolean(\n submodel.value.find(element =>\n element.value.toLocaleLowerCase() === enteredValue.toLocaleLowerCase()\n )\n )\n }\n if (type.toLocaleLowerCase() === 'range') {\n return enteredValue > Number(submodel.min) \n && enteredValue < Number(submodel.max);\n }\n return submodel.value === enteredValue;\n}\n\n// among all the submodels that match the demand,\n// at least one must be able to process it (i.e. all\n// technical requirements are met)\nmsg.payload.forEach(obj => {\n const mapped = obj.submodels.map(submodel => \n checkValue(submodel)\n );\n obj.possible = mapped.includes(true);\n});\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 590,
"y": 140,
"wires": [
[
"cb2883b1acc66248"
]
]
},
{
"id": "cbb098a2c48230a6",
"type": "function",
"z": "f96e455ab747ba2b",
"name": "final check",
"func": "// product can be ordered if every entries have at least\n// one capability associated to it, and if for every\n// capability, it's possible to do it (least english sentence ever made)\nlet doable = \n Object.entries(msg.payload).every(([_key, value]) => {\n if (!value || !value.length) return false;\n else return value.every(obj => obj.possible);\n })\n\n// if the unavailable array of submodel has at least\n// one element, then it's no doable, even if none of the\n// characteritics of the product require it/them\nmsg.doable = doable && msg.unavailable.length === 0;\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 710,
"y": 200,
"wires": [
[
"d925daf28fc2f63d",
"63da2e1e2126c8e2"
]
]
},
{
"id": "d925daf28fc2f63d",
"type": "debug",
"z": "f96e455ab747ba2b",
"name": "debug 2",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 880,
"y": 240,
"wires": []
},
{
"id": "63da2e1e2126c8e2",
"type": "link out",
"z": "f96e455ab747ba2b",
"name": "link out 2",
"mode": "link",
"links": [
"0430c5df11230321"
],
"x": 835,
"y": 200,
"wires": []
},
{
"id": "0430c5df11230321",
"type": "link in",
"z": "1320790a4546b4fd",
"name": "link in 6",
"links": [
"63da2e1e2126c8e2"
],
"x": 55,
"y": 80,
"wires": [
[
"d0ed24a50df785b3"
]
]
},
{
"id": "d0ed24a50df785b3",
"type": "switch",
"z": "1320790a4546b4fd",
"name": "",
"property": "doable",
"propertyType": "msg",
"rules": [
{
"t": "true"
},
{
"t": "false"
}
],
"checkall": "false",
"repair": false,
"outputs": 2,
"x": 160,
"y": 80,
"wires": [
[
"edd695b68f3090a3"
],
[
"8b057070221eb604"
]
]
},
{
"id": "edd695b68f3090a3",
"type": "change",
"z": "1320790a4546b4fd",
"name": "",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "[msg.baseInput]",
"tot": "jsonata"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 330,
"y": 80,
"wires": [
[
"9535db9724297388"
]
]
},
{
"id": "8b057070221eb604",
"type": "function",
"z": "1320790a4546b4fd",
"name": "unavailable list & filter blocking",
"func": "const blocking = {};\n\n// delete impossible entries and list blocking ones\nObject.entries(msg.payload).forEach(([key, value]) => {\n if (value.length === 0) {\n delete msg.payload[key];\n delete msg.baseInput[key];\n } \n else if (value.some(obj => !obj.possible))\n blocking[key] = value;\n \n});\n\n// store blocking characteritics to find a solution\nmsg.blocking = blocking;\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 210,
"y": 140,
"wires": [
[
"5624a09fb7ba3735"
]
]
},
{
"id": "5624a09fb7ba3735",
"type": "function",
"z": "1320790a4546b4fd",
"name": "find a solution!",
"func": "/**\n * Return an array of possible value(s) for a given\n * submodel, based on the model type & entered value.\n */\nconst findAlt = (submodel, value) => {\n const type = submodel.modelType?.name;\n const enteredValue = submodel.enteredValue;\n\n if (type.match(/SubmodelElement(Collection|List)/g)) {\n return submodel.value.map(element => element.value)\n }\n if (type.toLocaleLowerCase() === 'range') {\n const max = Number(submodel.max), min = Number(submodel.min);\n return enteredValue > max ? \n [Math.min(value, max) || max] : \n [Math.max(value, min) || min];\n }\n return submodel.value;\n}\n\n// put every value of base input inside an array\nObject.entries(msg.baseInput)\n .forEach(([key, val]) => msg.baseInput[key] = [val]);\n\n// if there's just stuff that was unavailable,\n// can send changed base input!\nif (!Object.keys(msg.blocking).length) {\n return msg;\n}\n\n// otherwise, if technical properties were not\n// met, find alternatives for each blocking value\nObject.entries(msg.blocking).forEach(([key, val]) => {\n // keep track of previously found value in order\n // to make sure a correct value in not overwritten\n // by a bad one\n let stuff = [];\n val.forEach(cap => {\n cap.submodels.forEach(sub => {\n const find = findAlt(sub, stuff.at(0));\n stuff = find;\n msg.baseInput[key] = find;\n });\n });\n});\n\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 380,
"y": 200,
"wires": [
[
"d03ec6057ef1ad69",
"e09f506e27da74e5"
]
]
},
{
"id": "d03ec6057ef1ad69",
"type": "function",
"z": "1320790a4546b4fd",
"name": "gathering",
"func": "const propositions = [];\n/**\n * Function that takes multiple arrays and returns the\n * cartesian products of all of them\n */\nconst cartesian = (...a) => a.reduce((a, b) => a.flatMap(d => b.map(e => [d, e].flat())));\n\n// cartesian product of all possible values\n// to create as much proposals as possible!\ncartesian(...Object.values(msg.baseInput)).forEach(arr => {\n node.warn(arr);\n const copy = {...msg.baseInput};\n let i = 0;\n Object.keys(copy).forEach(key => copy[key] = arr.at(i++));\n propositions.push(copy);\n})\n\nmsg.payload = propositions;\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 480,
"y": 140,
"wires": [
[
"9535db9724297388"
]
]
},
{
"id": "aec0270a6b3a57e9",
"type": "debug",
"z": "1320790a4546b4fd",
"name": "debug 3",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 860,
"y": 120,
"wires": []
},
{
"id": "8f998ce344f595e0",
"type": "ui_list",
"z": "1320790a4546b4fd",
"group": "859d724c411b6b56",
"name": "proposition list",
"order": 2,
"width": "0",
"height": "0",
"lineType": "three",
"actionType": "click",
"allowHTML": false,
"outputs": 1,
"topic": "",
"x": 400,
"y": 420,
"wires": [
[
"86cd9cacec78bd7e"
]
]
},
{
"id": "e09f506e27da74e5",
"type": "debug",
"z": "1320790a4546b4fd",
"name": "debug 4",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 560,
"y": 200,
"wires": []
},
{
"id": "9535db9724297388",
"type": "function",
"z": "1320790a4546b4fd",
"name": "proposition list",
"func": "// propositions into a list :)\nmsg.payload = msg.payload.map(proposition => ({\n title: `${msg.available.map(av => av.capability).join(', ')}`,\n description: `${JSON.stringify(proposition)}`\n}));\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 680,
"y": 80,
"wires": [
[
"aec0270a6b3a57e9",
"b14a72981ce166b8"
]
]
},
{
"id": "b506aa1a68dc8cee",
"type": "link in",
"z": "1320790a4546b4fd",
"name": "link in 7",
"links": [
"b14a72981ce166b8"
],
"x": 225,
"y": 360,
"wires": [
[
"ef4dd18cabed24db",
"e14a5947be3648b4",
"8f998ce344f595e0"
]
]
},
{
"id": "b14a72981ce166b8",
"type": "link out",
"z": "1320790a4546b4fd",
"name": "link out 3",
"mode": "link",
"links": [
"b506aa1a68dc8cee"
],
"x": 815,
"y": 80,
"wires": []
},
{
"id": "ef4dd18cabed24db",
"type": "switch",
"z": "1320790a4546b4fd",
"name": "",
"property": "doable",
"propertyType": "msg",
"rules": [
{
"t": "true"
},
{
"t": "false"
}
],
"checkall": "true",
"repair": false,
"outputs": 2,
"x": 350,
"y": 320,
"wires": [
[
"0b0821ecc3f62621"
],
[
"d9c4214abbf157df"
]
]
},
{
"id": "b09b0367e9a0a29a",
"type": "ui_ui_control",
"z": "1320790a4546b4fd",
"name": "",
"events": "all",
"x": 740,
"y": 460,
"wires": [
[]
]
},
{
"id": "e14a5947be3648b4",
"type": "change",
"z": "1320790a4546b4fd",
"name": "proposition",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "Proposition",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 390,
"y": 460,
"wires": [
[
"b09b0367e9a0a29a"
]
]
},
{
"id": "af92141334e5796b",
"type": "ui_text",
"z": "1320790a4546b4fd",
"group": "859d724c411b6b56",
"order": 1,
"width": 0,
"height": 0,
"name": "",
"label": "",
"format": "{{msg.payload}}",
"layout": "col-center",
"className": "",
"x": 650,
"y": 340,
"wires": []
},
{
"id": "7b6db2d58d8d3cf7",
"type": "ui_button",
"z": "1320790a4546b4fd",
"name": "back",
"group": "859d724c411b6b56",
"order": 3,
"width": 0,
"height": 0,
"passthru": false,
"label": "Back to order",
"tooltip": "",
"color": "",
"bgcolor": "",
"className": "",
"icon": "",
"payload": "Workpiece order",
"payloadType": "str",
"topic": "topic",
"topicType": "msg",
"x": 590,
"y": 500,
"wires": [
[
"b09b0367e9a0a29a"
]
]
},
{
"id": "d9c4214abbf157df",
"type": "change",
"z": "1320790a4546b4fd",
"name": "alt",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "The product that you requested is not available, but here are some alternatives that are similar to what you asked",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 510,
"y": 340,
"wires": [
[
"af92141334e5796b"
]
]
},
{
"id": "0b0821ecc3f62621",
"type": "change",
"z": "1320790a4546b4fd",
"name": "good!",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "The product that you requested is available, please review your order",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 510,
"y": 300,
"wires": [
[
"af92141334e5796b"
]
]
},
{
"id": "02eedb0262828d82",
"type": "catch",
"z": "1320790a4546b4fd",
"name": "",
"scope": [
"d03ec6057ef1ad69"
],
"uncaught": false,
"x": 70,
"y": 420,
"wires": [
[
"90f1b50212148ae0"
]
]
},
{
"id": "90f1b50212148ae0",
"type": "change",
"z": "1320790a4546b4fd",
"name": "err",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "[]",
"tot": "json"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 190,
"y": 420,
"wires": [
[
"8f998ce344f595e0",
"8f5d8ce91dd46f18",
"e14a5947be3648b4"
]
]
},
{
"id": "0f6401f582448d0c",
"type": "change",
"z": "1320790a4546b4fd",
"name": "not good",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "The product that you requested is not available as of now. Please order something else!",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 500,
"y": 380,
"wires": [
[
"af92141334e5796b"
]
]
},
{
"id": "86cd9cacec78bd7e",
"type": "change",
"z": "1320790a4546b4fd",
"name": "confirmation",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "Confirmation",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 570,
"y": 420,
"wires": [
[
"b09b0367e9a0a29a",
"3eedc2dd60786ae3"
]
]
},
{
"id": "3eedc2dd60786ae3",
"type": "ui_text",
"z": "1320790a4546b4fd",
"group": "25611d1488853208",
"order": 0,
"width": 0,
"height": 0,
"name": "",
"label": "",
"format": "Your product has been ordered. Thank you!",
"layout": "col-center",
"className": "",
"x": 730,
"y": 420,
"wires": []
}
]
\ No newline at end of file
{} {
\ No newline at end of file "2282c53e6f2d220c": {
"user": "industrie",
"password": "industrie"
},
"df9ec70032434b59": {},
"5850cb65c596909b": {}
}
\ No newline at end of file
...@@ -2,7 +2,11 @@ ...@@ -2,7 +2,11 @@
"name": "DF-Dashboard", "name": "DF-Dashboard",
"description": "A dashboard for the digital factory of the Hochschule Emden/Leer", "description": "A dashboard for the digital factory of the Hochschule Emden/Leer",
"version": "0.0.1", "version": "0.0.1",
"dependencies": {}, "dependencies": {
"node-red-dashboard": "3.4.0",
"node-red-node-ui-list": "0.3.6",
"node-red-contrib-ui-editor": "0.0.1"
},
"node-red": { "node-red": {
"settings": { "settings": {
"flowFile": "flow.json", "flowFile": "flow.json",
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment