UNPKG

@ifp-software/node-red-contrib-oee-ai-connector

Version:

Easily connect your production machines to oee.ai – The Industry 4.0 solution for OEE optimization.

865 lines 25.2 kB
[ { "id": "d7a9aa05686055cd", "type": "subflow", "name": "Get Shifts from MIP", "info": "", "category": "", "in": [ { "x": 40, "y": 80, "wires": [ { "id": "08422e45ec1e2ee7" } ] } ], "out": [ { "x": 1440, "y": 80, "wires": [ { "id": "cf7a26fbe3e06c3c", "port": 0 } ] } ], "env": [], "meta": {}, "color": "#DDAA99" }, { "id": "73c73b822cd7b597", "type": "change", "z": "d7a9aa05686055cd", "name": "Delete META data", "rules": [ { "t": "delete", "p": "payload[0]", "pt": "msg" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 890, "y": 80, "wires": [ [ "cf7a26fbe3e06c3c" ] ] }, { "id": "1b236955d0a8025e", "type": "change", "z": "d7a9aa05686055cd", "name": "Clean up for next requests", "rules": [ { "t": "delete", "p": "headers", "pt": "msg" }, { "t": "delete", "p": "url", "pt": "msg" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 660, "y": 80, "wires": [ [ "73c73b822cd7b597" ] ] }, { "id": "85c894ddeb73fef4", "type": "http request", "z": "d7a9aa05686055cd", "name": "service call to MIP", "method": "POST", "ret": "obj", "paytoqs": "ignore", "url": "", "tls": "", "persist": false, "proxy": "", "insecureHTTPParser": false, "authType": "", "senderr": false, "headers": [], "x": 410, "y": 80, "wires": [ [ "1b236955d0a8025e", "8569908875de067d" ] ] }, { "id": "08422e45ec1e2ee7", "type": "function", "z": "d7a9aa05686055cd", "name": "build request", "func": "msg.payload = { \n \"params\": [], \n \"columns\": [], \n \"returnAsObject\": true,\n \"languageKey\": msg.languageKey\n}\n\nmsg.url = msg.baseUrl + \"/data/MDMFDayModel/list?X-Access-Id=\" + msg.xAccessId\n\nlet basic_encrypted = \"Basic \" + new Buffer(msg.user + ':' + msg.password).toString('base64')\n\nmsg.headers = { \n \"Content-Type\": \"application/json\",\n \"Authorization\": basic_encrypted\n}\n\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 190, "y": 80, "wires": [ [ "85c894ddeb73fef4" ] ] }, { "id": "cf7a26fbe3e06c3c", "type": "function", "z": "d7a9aa05686055cd", "name": "Create shifts and breaks for all DayModels", "func": "function formatDateToRRule(date) {\n const year = date.getUTCFullYear();\n const month = (\"0\" + (date.getUTCMonth() + 1)).slice(-2);\n const day = (\"0\" + date.getUTCDate()).slice(-2);\n const hours = (\"0\" + date.getUTCHours()).slice(-2);\n const minutes = (\"0\" + date.getUTCMinutes()).slice(-2);\n const seconds = (\"0\" + date.getUTCSeconds()).slice(-2);\n return `${year}${month}${day}T${hours}${minutes}${seconds}Z`;\n}\n\nfunction calculateTimeDifference(startSeconds, endSeconds) {\n // calculate the difference in seconds\n let differenceInSeconds = endSeconds - startSeconds;\n \n // special case where the shift goes to the next day\n if (endSeconds < startSeconds){\n differenceInSeconds = 86400 - startSeconds + endSeconds;\n }\n // calculate hours and minutes\n let hours = Math.floor(differenceInSeconds / 3600);\n let minutes = Math.floor((differenceInSeconds % 3600) / 60);\n // return as string in the format HH:MM\n return `${(\"0\" + hours).slice(-2)}:${(\"0\" + minutes).slice(-2)}`;\n}\n\nfunction timeFromMidnight(seconds) {\n // Create a new Date object for the current date\n let date = new Date();\n // Set the time to 00:00:00\n date.setHours(0, 0, 0, 0);\n // Add the seconds to the date object\n date.setSeconds(seconds);\n // Return the date object\n return date;\n}\n\n\n// DTSTART:20230723T040000Z\\nRRULE:FREQ=DAILY;BYDAY=MO;INTERVAL=1;UNTIL=20230730T000000Z\n\n// freq\nconst freq = \"DAILY\"\n\n// interval\nconst interval = 1\n\n// byday\nconst byday = \"MO,TU,WE,TH,FR,SA,SU\"\n\n// shiftsData\n\n\n\n// iterate over dayModels\nmsg.payload.forEach(dayModel => {\n msg.shiftsData = [];\n dayModel = dayModel.obj;\n // possible shifts\n for(let i=1; i < 5;i++){\n let currShiftName = dayModel[`mf_daymodel.shift${i}.type`]\n let currShiftStart = dayModel[`mf_daymodel.shift${i}.start`];\n let currShiftEnd = dayModel[`mf_daymodel.shift${i}.end`];\n \n // filter unused shifts\n if (currShiftStart === 0 && currShiftEnd === 0){\n continue;\n }\n // dtstart calculate hour from seconds since 00:00\n let dtstartDate = timeFromMidnight(currShiftStart);\n let dtstart = formatDateToRRule(dtstartDate); \n \n\n let newShift = { \n \"shiftName\": `shift${i}`, \n \"rrule\": `DTSTART:${dtstart}\\nRRULE:FREQ=${freq};BYDAY=${byday};INTERVAL=${interval}`, \n \"duration\": calculateTimeDifference(currShiftStart, currShiftEnd), \n \"mode\": \"work\", \n \"color\": \"azure\" \n };\n \n msg.shiftsData.push(newShift);\n \n // possible breaks\n for(let j=1; j < 7;j++){\n let currBreakStart = dayModel[`mf_daymodel.shift${i}.break${j}.start`];\n let currBreakEnd = dayModel[`mf_daymodel.shift${i}.break${j}.end`];\n \n \n // filter unused breaks\n if (currBreakStart === 0 && currBreakEnd === 0){\n continue;\n }\n \n // dtstart calculate hour from seconds since 00:00\n dtstartDate = timeFromMidnight(currBreakStart);\n dtstart = formatDateToRRule(dtstartDate); \n \n let newBreak = { \n \"shiftName\": `break${j}`, \n \"rrule\": `DTSTART:${dtstart}\\nRRULE:FREQ=${freq};BYDAY=${byday};INTERVAL=${interval}`, \n \"duration\": calculateTimeDifference(currBreakStart, currBreakEnd), \n \"mode\": \"pause\", \n \"color\": \"indigo\" \n };\n \n msg.shiftsData.push(newBreak);\n }\n \n }\n msg.scheduleName = dayModel[\"mf_daymodel.designation\"] ?? \"No Name in MIP\";\n node.send(msg);\n})", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1190, "y": 80, "wires": [ [] ] }, { "id": "8569908875de067d", "type": "debug", "z": "d7a9aa05686055cd", "name": "service call MIP", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "statusCode", "targetType": "msg", "statusVal": "", "statusType": "auto", "x": 620, "y": 120, "wires": [] }, { "id": "e4de7c01e09a776f", "type": "subflow", "name": "Post shift", "info": "", "category": "", "in": [ { "x": 200, "y": 400, "wires": [ { "id": "a49b15b920a72364" } ] } ], "out": [], "env": [], "meta": {}, "color": "#DDAA99" }, { "id": "a49b15b920a72364", "type": "function", "z": "e4de7c01e09a776f", "name": "Formatting json payload", "func": "msg.headers = {\n \"Authorization\": \"Bearer \" + msg.bearerToken,\n \"Content-Type\": \"application/vnd.api+json\"\n};\n\nmsg.payload = {\n \"data\": {\n \"type\": \"shifts\",\n \"attributes\": {\n \"name\": msg.shiftName,\n \"rrule\": msg.rrule,\n \"duration\": msg.duration,\n \"mode\": msg.mode,\n \"color\": msg.color\n },\n \"relationships\": {\n \"schedule\": {\n \"data\": {\n \"type\": \"schedules\",\n \"id\": msg.schedule\n }\n }\n }\n }\n};\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 410, "y": 400, "wires": [ [ "90b0febb18e8d827" ] ] }, { "id": "90b0febb18e8d827", "type": "http request", "z": "e4de7c01e09a776f", "name": "POST shift", "method": "POST", "ret": "obj", "paytoqs": "ignore", "url": "https://api.oee.ai/shifts", "tls": "", "persist": false, "proxy": "", "authType": "", "senderr": false, "x": 610, "y": 400, "wires": [ [ "e3a52c265232f222", "96753bc5dfa1ce82" ] ] }, { "id": "e3a52c265232f222", "type": "change", "z": "e4de7c01e09a776f", "name": "Delete response header", "rules": [ { "t": "delete", "p": "headers", "pt": "msg" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 830, "y": 400, "wires": [ [ "41debf62367c281b" ] ] }, { "id": "41debf62367c281b", "type": "debug", "z": "e4de7c01e09a776f", "name": "Response from oee.ai", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "statusVal": "", "statusType": "auto", "x": 1080, "y": 400, "wires": [] }, { "id": "96753bc5dfa1ce82", "type": "debug", "z": "e4de7c01e09a776f", "name": "Post Shift", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "statusCode", "targetType": "msg", "statusVal": "", "statusType": "auto", "x": 780, "y": 440, "wires": [] }, { "id": "fd9e8ae80b46227a", "type": "subflow", "name": "Send shifts to oee.ai", "info": "", "category": "", "in": [ { "x": 0, "y": 80, "wires": [ { "id": "7e6da3c796a23dc8" } ] } ], "out": [], "env": [], "meta": {}, "color": "#DDAA99" }, { "id": "8632f17598829578", "type": "subflow:e4de7c01e09a776f", "z": "fd9e8ae80b46227a", "name": "", "x": 840, "y": 80, "wires": [] }, { "id": "0e5877e09b93e4ad", "type": "change", "z": "fd9e8ae80b46227a", "name": "Mapping shift attributes", "rules": [ { "t": "set", "p": "shiftName", "pt": "msg", "to": "payload.shiftName", "tot": "msg" }, { "t": "set", "p": "rrule", "pt": "msg", "to": "payload.rrule", "tot": "msg" }, { "t": "set", "p": "duration", "pt": "msg", "to": "payload.duration", "tot": "msg" }, { "t": "set", "p": "mode", "pt": "msg", "to": "payload.mode", "tot": "msg" }, { "t": "set", "p": "color", "pt": "msg", "to": "msg.payload.color", "tot": "msg" }, { "t": "set", "p": "schedule", "pt": "msg", "to": "scheduleId", "tot": "msg" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 630, "y": 80, "wires": [ [ "8632f17598829578" ] ] }, { "id": "fc7521805a23e0f7", "type": "split", "z": "fd9e8ae80b46227a", "name": "Split shifts", "splt": "\\n", "spltType": "str", "arraySplt": 1, "arraySpltType": "len", "stream": false, "addname": "", "x": 410, "y": 80, "wires": [ [ "0e5877e09b93e4ad" ] ] }, { "id": "7e6da3c796a23dc8", "type": "change", "z": "fd9e8ae80b46227a", "name": "Set payload to shiftsData", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "shiftsData", "tot": "msg" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 190, "y": 80, "wires": [ [ "fc7521805a23e0f7" ] ] }, { "id": "3ef6e3cb08fd4645", "type": "subflow", "name": "Post schedule", "info": "", "category": "", "in": [ { "x": 360, "y": 280, "wires": [ { "id": "16f20561eeb96ab6" } ] } ], "out": [ { "x": 1180, "y": 280, "wires": [ { "id": "db876e05e8954483", "port": 0 } ] } ], "env": [], "meta": {}, "color": "#DDAA99" }, { "id": "16f20561eeb96ab6", "type": "function", "z": "3ef6e3cb08fd4645", "name": "Formatting json payload", "func": "msg.headers = {\n \"Authorization\": \"Bearer \" + msg.bearerToken,\n \"Content-Type\": \"application/vnd.api+json\"\n};\n\nmsg.payload = {\n \"data\": {\n \"type\": \"schedules\",\n \"attributes\": {\n \"name\": msg.scheduleName,\n \"end-based\": msg[\"end-based\"]\n },\n \"relationships\": {\n \"location\": {\n \"data\": {\n \"type\": \"locations\",\n \"id\": msg.location\n }\n }\n }\n }\n};\n\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 550, "y": 280, "wires": [ [ "8b789b3c687e3db2" ] ] }, { "id": "8b789b3c687e3db2", "type": "http request", "z": "3ef6e3cb08fd4645", "name": "POST schedule", "method": "POST", "ret": "obj", "paytoqs": "ignore", "url": "https://api.oee.ai/schedules", "tls": "", "persist": false, "proxy": "", "authType": "", "senderr": false, "x": 780, "y": 280, "wires": [ [ "db876e05e8954483" ] ] }, { "id": "db876e05e8954483", "type": "change", "z": "3ef6e3cb08fd4645", "name": "Delete response header", "rules": [ { "t": "delete", "p": "headers", "pt": "msg" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 1010, "y": 280, "wires": [ [] ] }, { "id": "96e5bd1b60b318b2", "type": "subflow", "name": "Send schedules to oee.ai", "info": "", "category": "", "in": [ { "x": 480, "y": 340, "wires": [ { "id": "15ad974df513bfef" } ] } ], "out": [ { "x": 1320, "y": 340, "wires": [ { "id": "9ce0601df1e13c43", "port": 0 } ] } ], "env": [], "meta": {}, "color": "#DDAA99" }, { "id": "daf88fda59f965b3", "type": "switch", "z": "96e5bd1b60b318b2", "name": "Check if schedule already exists", "property": "statusCode", "propertyType": "msg", "rules": [ { "t": "eq", "v": "422", "vt": "num" }, { "t": "else" } ], "checkall": "false", "repair": false, "outputs": 2, "x": 870, "y": 340, "wires": [ [], [ "9ce0601df1e13c43" ] ] }, { "id": "15ad974df513bfef", "type": "subflow:3ef6e3cb08fd4645", "z": "96e5bd1b60b318b2", "name": "", "x": 610, "y": 340, "wires": [ [ "daf88fda59f965b3", "24c71de118817ecb" ] ] }, { "id": "9ce0601df1e13c43", "type": "change", "z": "96e5bd1b60b318b2", "name": "Save schedule id", "rules": [ { "t": "set", "p": "scheduleId", "pt": "msg", "to": "payload.data.id", "tot": "msg" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 1150, "y": 340, "wires": [ [] ] }, { "id": "24c71de118817ecb", "type": "debug", "z": "96e5bd1b60b318b2", "name": "Post schedules", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "statusCode", "targetType": "msg", "statusVal": "", "statusType": "auto", "x": 820, "y": 400, "wires": [] }, { "id": "9e66472980aab6f0", "type": "tab", "label": "MIP Synchronizing shifts", "disabled": false, "info": "", "env": [] }, { "id": "167466639d86460a", "type": "change", "z": "9e66472980aab6f0", "name": "Mapping schedule attributes", "rules": [ { "t": "set", "p": "end-based", "pt": "msg", "to": "false", "tot": "bool" }, { "t": "set", "p": "location", "pt": "msg", "to": "", "tot": "str" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 1020, "y": 140, "wires": [ [ "5c8f83a28d8986f3" ] ] }, { "id": "7fae43045599e197", "type": "comment", "z": "9e66472980aab6f0", "name": "^^ set schedule attributes", "info": "Format your message to the data model of oee.ai\nThen map your message values to the predefined\nmessage values in the change node", "x": 1010, "y": 180, "wires": [] }, { "id": "6ab2cecafd2430ea", "type": "comment", "z": "9e66472980aab6f0", "name": "^^ enter your oee.ai API token", "info": "You can find your API Token on oee.ai", "x": 760, "y": 180, "wires": [] }, { "id": "aa7a250d8a9016fa", "type": "change", "z": "9e66472980aab6f0", "name": "Set API Token", "rules": [ { "t": "set", "p": "bearerToken", "pt": "msg", "to": "", "tot": "str" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 720, "y": 140, "wires": [ [ "167466639d86460a" ] ] }, { "id": "5c8f83a28d8986f3", "type": "subflow:96e5bd1b60b318b2", "z": "9e66472980aab6f0", "name": "", "x": 1290, "y": 140, "wires": [ [ "9f59e0e470ee9951" ] ] }, { "id": "9f59e0e470ee9951", "type": "subflow:fd9e8ae80b46227a", "z": "9e66472980aab6f0", "name": "", "x": 1540, "y": 140, "wires": [] }, { "id": "a01afc49bb617478", "type": "change", "z": "9e66472980aab6f0", "name": "set settings", "rules": [ { "t": "set", "p": "baseUrl", "pt": "msg", "to": "", "tot": "str" }, { "t": "set", "p": "user", "pt": "msg", "to": "", "tot": "str" }, { "t": "set", "p": "password", "pt": "msg", "to": "", "tot": "str" }, { "t": "set", "p": "xAccessId", "pt": "msg", "to": "", "tot": "str" }, { "t": "set", "p": "languageKey", "pt": "msg", "to": "en", "tot": "str" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 290, "y": 140, "wires": [ [ "4ac3005169152875" ] ] }, { "id": "e3eeeb78c36d0d76", "type": "inject", "z": "9e66472980aab6f0", "name": "Once", "props": [], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "x": 110, "y": 140, "wires": [ [ "a01afc49bb617478" ] ] }, { "id": "4ac3005169152875", "type": "subflow:d7a9aa05686055cd", "z": "9e66472980aab6f0", "name": "Get Shifts from MIP", "x": 490, "y": 140, "wires": [ [ "aa7a250d8a9016fa" ] ] }, { "id": "c9acf0f4fa89423e", "type": "comment", "z": "9e66472980aab6f0", "name": "^^ configure your settings", "info": "", "x": 330, "y": 180, "wires": [] }, { "id": "fae09fa111f0b325", "type": "comment", "z": "9e66472980aab6f0", "name": "^^Click me", "info": "", "x": 110, "y": 180, "wires": [] } ]