Skip to content

Instantly share code, notes, and snippets.

@WolfwithSword
Forked from mkosmo/bambu_mqtt.json
Last active September 20, 2024 14:37
Show Gist options
  • Save WolfwithSword/e3e4dc4f00629cc047b7cefd70d7b350 to your computer and use it in GitHub Desktop.
Save WolfwithSword/e3e4dc4f00629cc047b7cefd70d7b350 to your computer and use it in GitHub Desktop.
Node-RED Flow - BambuLab X1 MQTT Relay for Home Assistant MQTT Auto-Discovery
[
{
"id": "40b2e704eefd62e1",
"type": "group",
"z": "fbda6ab16491b918",
"name": "Bed Mesh Parser",
"style": {
"stroke": "#92d04f",
"fill": "#9363b7",
"fill-opacity": "0.16",
"label": true,
"color": "#92d04f"
},
"nodes": [
"8cbcc2518bb88578",
"88c5fd6ecd7e759c",
"8f497caa1a935bbc",
"b13c20fc7ba936ff",
"cca119c7dfb496a6",
"7de5e9abab4d8338",
"3283e43cad3529ae",
"fc971be971f64ba7",
"e72d7015e57c20f8",
"05622166b0ca0330",
"b360255a177cd67a",
"ac916f22c82df203",
"24cc9339f7d7c497",
"320a9e3ba5045959",
"80f87bc2b2de479b",
"9049759452122840",
"37a495c063566b97",
"91a9f3a785e5167e",
"36fdeabb54b38c86",
"8c3888bbf1ce213c",
"b605d208757fde56",
"cc539923f0b07cb5",
"1e2b1247f1d0c0e1",
"c154af220552f516",
"29b479f5aa4d6618",
"4a5fb4819bb0abdd",
"6c9219a2f8830bd1"
],
"x": 1694,
"y": 1839,
"w": 1012,
"h": 442
},
{
"id": "8cbcc2518bb88578",
"type": "mqtt out",
"z": "fbda6ab16491b918",
"g": "40b2e704eefd62e1",
"name": "Home Assistant",
"topic": "",
"qos": "",
"retain": "",
"respTopic": "",
"contentType": "",
"userProps": "",
"correl": "",
"expiry": "",
"broker": "489094618c340eef",
"x": 2600,
"y": 2240,
"wires": []
},
{
"id": "88c5fd6ecd7e759c",
"type": "function",
"z": "fbda6ab16491b918",
"g": "40b2e704eefd62e1",
"name": "Printer State",
"func": "\nmsg.machine_name = \"X1C_\" + \"{PRINTER_NAME}\"; \nlet old = msg.topic;\nif(msg.raw == []) {\n msg.payload = \"None\";\n}\nlet payload = msg.payload;\nif(msg.payload == undefined || msg.payload == \"\") {\n return;\n}\nif (msg.payload != \"None\" && !msg.payload.includes(\"MQTT\")) {\n msg.payload = \"Ready\";\n msg.topic = \"homeassistant/sensor/\" + msg.machine_name + \"/\" + msg.topic + \"/state\";\n node.send(msg);\n}\nelse {\n msg.topic = \"homeassistant/sensor/\" + msg.machine_name + \"/\" + msg.topic + \"/state\";\n node.send(msg);\n}\n\nmsg.payload = { \"Visualizer\": \"https://www.wolfwithsword.com/bambu-printer-bed-visualizer/\" };\nmsg.topic = \"homeassistant/sensor/\" + msg.machine_name + \"/\" + old + \"/attr\";\n\nif (payload != \"None\") {\n msg.payload[\"Data\"] = payload;\n if (payload.includes(\"MQTT\")) {\n msg.payload['Data'] = \"homeassistant/sensor/\" + msg.machine_name + \"/\" + old + \"/raw\";\n }\n}\nnode.send(msg);\n\n\nmsg.topic = \"homeassistant/sensor/\" + msg.machine_name + \"/\" + old + \"/raw\";\nmsg.payload = msg.raw;\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 2570,
"y": 2160,
"wires": [
[
"1e2b1247f1d0c0e1"
]
]
},
{
"id": "8f497caa1a935bbc",
"type": "function",
"z": "fbda6ab16491b918",
"g": "40b2e704eefd62e1",
"name": "Printer Config",
"func": "let data = {};\nlet payload = {};\nlet device = {};\n\nfunction getFriendlyName(str) {\n var i, word = str.split('_');\n for (i = 0; i < word.length; i++) {\n word[i] = word[i].charAt(0).toUpperCase() + word[i].slice(1);\n }\n return word.join(' ');\n}\nmsg.machine_name = \"X1C_\" + \"{PRINTER_NAME}\";\nlet printer_name = msg.machine_name;\n\nlet type = \"sensor\";\nlet base_topic = \"homeassistant/\"+ type + \"/\" + msg.machine_name + \"/\" + msg.topic;\ndata.topic = base_topic + \"/config\";\npayload.name = getFriendlyName(msg.topic);\n\ndevice.identifiers = [];\ndevice.identifiers[0] = msg.machine_name;\n\ndevice.manufacturer = \"Bambu Labs\";\ndevice.model = \"X1C\";\ndevice.name = msg.machine_name;\nif( msg.icon != undefined) {\n payload.icon = msg.icon\n}\n\npayload.device = device;\npayload.unique_id = msg.machine_name + \"_\" + msg.topic;\npayload.object_id = payload.unique_id;\n\nif (msg.device_class != undefined)\n payload.device_class = msg.device_class;\n\nif (msg.unit_of_measurement != undefined)\n payload.unit_of_measurement = msg.unit_of_measurement;\n\n\npayload.state_topic = base_topic + \"/state\";\npayload.json_attributes_topic = base_topic + \"/attr\";\ndata.payload = payload\n\ndata.qos = 1;\ndata.retain = true;\nnode.send(data);\n",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 2560,
"y": 2120,
"wires": [
[
"1e2b1247f1d0c0e1"
]
]
},
{
"id": "b13c20fc7ba936ff",
"type": "mqtt in",
"z": "fbda6ab16491b918",
"g": "40b2e704eefd62e1",
"name": "Bambu X1C {PRINTER_NAME}",
"topic": "device/{PRINTER_SERIAL}/report",
"qos": "2",
"datatype": "json",
"broker": "{GENERATED_PRINTER_MQTT_ID}",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 1830,
"y": 2060,
"wires": [
[
"cca119c7dfb496a6"
]
]
},
{
"id": "cca119c7dfb496a6",
"type": "json",
"z": "fbda6ab16491b918",
"g": "40b2e704eefd62e1",
"name": "",
"property": "payload.print",
"action": "obj",
"pretty": false,
"x": 2010,
"y": 2060,
"wires": [
[
"7de5e9abab4d8338"
]
]
},
{
"id": "7de5e9abab4d8338",
"type": "function",
"z": "fbda6ab16491b918",
"g": "40b2e704eefd62e1",
"name": "Inject Machine Details",
"func": "let machine_name = \"{PRINTER_NAME}\";\nlet machine_serial = \"{PRINTER_SERIAL}\";\nlet manufacturer = \"Bambu Labs\";\nlet model = \"X1 Carbon\"\n\n\nif(msg.payload.mc_print != undefined) {\n msg.payload.mc_print.machine_name = machine_name;\n msg.payload.mc_print.machine_serial = machine_serial;\n msg.payload.mc_print.manufacturer = manufacturer;\n if(msg.payload.mc_print.param.includes(\"[AMS]\")) {\n msg.payload.mc_print.model = \"AMS\";\n }\n else {\n msg.payload.mc_print.model = model;\n node.send(msg);\n }\n}\n",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1820,
"y": 2100,
"wires": [
[
"3283e43cad3529ae"
]
]
},
{
"id": "3283e43cad3529ae",
"type": "function",
"z": "fbda6ab16491b918",
"g": "40b2e704eefd62e1",
"name": "Cull Fail Msg",
"func": "if(msg.payload != undefined && Object.keys(msg.payload).length > 0){\n node.send(msg);\n}",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 2010,
"y": 2100,
"wires": [
[
"fc971be971f64ba7"
]
]
},
{
"id": "fc971be971f64ba7",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "40b2e704eefd62e1",
"name": "",
"property": "payload.mc_print.param",
"propertyType": "msg",
"rules": [
{
"t": "regex",
"v": "\\[BMC\\] X\\d+\\.\\d+ Y\\d+\\.\\d+,z_c=",
"vt": "str",
"case": false
}
],
"checkall": "true",
"repair": false,
"outputs": 1,
"x": 1770,
"y": 2140,
"wires": [
[
"e72d7015e57c20f8"
]
]
},
{
"id": "e72d7015e57c20f8",
"type": "function",
"z": "fbda6ab16491b918",
"g": "40b2e704eefd62e1",
"name": "Parse coord",
"func": "let param = msg.payload.mc_print.param;\nlet x = param.match(/X(\\d+\\.\\d+)/)[1];\nlet y = param.match(/Y(\\d+\\.\\d+)/)[1];\nlet z = param.match(/z_c=\\s+(-?\\d+\\.\\d+)/)[1];\nlet coords = [x, y, z];\nmsg.payload = {\"coord\": {\"x\": parseFloat(x), \"y\":parseFloat(y), \"z\":parseFloat(z)}};\n\nlet abl = flow.get('abl');\nabl.push(msg.payload);\nnode.send(msg);\n",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1910,
"y": 2140,
"wires": [
[]
]
},
{
"id": "05622166b0ca0330",
"type": "mqtt in",
"z": "fbda6ab16491b918",
"g": "40b2e704eefd62e1",
"name": "HomeAssistant In",
"topic": "homeassistant/sensor/X1C_{PRINTER_NAME}/stage/state",
"qos": "2",
"datatype": "utf8",
"broker": "489094618c340eef",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 1800,
"y": 2020,
"wires": [
[
"ac916f22c82df203"
]
]
},
{
"id": "b360255a177cd67a",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "40b2e704eefd62e1",
"name": "",
"property": "payload",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "Auto bed leveling",
"vt": "str"
},
{
"t": "eq",
"v": "Offline",
"vt": "str"
},
{
"t": "eq",
"v": "Idle",
"vt": "str"
},
{
"t": "eq",
"v": "Printing",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 4,
"x": 2070,
"y": 2000,
"wires": [
[
"24cc9339f7d7c497",
"8c3888bbf1ce213c"
],
[
"24cc9339f7d7c497",
"8c3888bbf1ce213c"
],
[
"29b479f5aa4d6618"
],
[
"29b479f5aa4d6618"
]
]
},
{
"id": "ac916f22c82df203",
"type": "rbe",
"z": "fbda6ab16491b918",
"g": "40b2e704eefd62e1",
"name": "",
"func": "rbe",
"gap": "",
"start": "",
"inout": "out",
"septopics": true,
"property": "payload",
"topi": "topic",
"x": 1950,
"y": 2020,
"wires": [
[
"b360255a177cd67a"
]
]
},
{
"id": "24cc9339f7d7c497",
"type": "change",
"z": "fbda6ab16491b918",
"g": "40b2e704eefd62e1",
"name": "",
"rules": [
{
"t": "set",
"p": "abl",
"pt": "flow",
"to": "[]",
"tot": "json"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 2350,
"y": 2000,
"wires": [
[]
]
},
{
"id": "320a9e3ba5045959",
"type": "delay",
"z": "fbda6ab16491b918",
"g": "40b2e704eefd62e1",
"name": "",
"pauseType": "delay",
"timeout": "1",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"x": 2300,
"y": 2080,
"wires": [
[
"9049759452122840"
]
]
},
{
"id": "80f87bc2b2de479b",
"type": "inject",
"z": "fbda6ab16491b918",
"g": "40b2e704eefd62e1",
"name": "Init",
"props": [
{
"p": "topic",
"vt": "str"
},
{
"p": "payload"
}
],
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": 0.1,
"topic": "bed_mesh_data",
"payload": "None",
"payloadType": "str",
"x": 2030,
"y": 1940,
"wires": [
[
"24cc9339f7d7c497",
"8c3888bbf1ce213c"
]
]
},
{
"id": "9049759452122840",
"type": "function",
"z": "fbda6ab16491b918",
"g": "40b2e704eefd62e1",
"name": "Create Matrix",
"func": "let abl = flow.get('abl');\nif(abl.length > 0) {\n let setX = new Set();\n let setY = new Set();\n for (let c of abl) {\n setX.add(c.coord.x);\n setY.add(c.coord.y);\n }\n let xs = Array.from(setX).sort(function (a, b) {\n return a - b;\n });\n let ys = Array.from(setY).sort(function (a, b) {\n return a - b;\n });\n\n\n let data = new Array(ys.length).fill(0).map(() => new Array(xs.length).fill(0));\n for (var c of abl) {\n let coord = c.coord;\n let x = xs.indexOf(coord.x);\n let y = ys.indexOf(coord.y);\n data[y][x] = coord.z;\n }\n msg.payload = data;\n msg.raw = data;\n node.send(msg);\n}",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 2300,
"y": 2120,
"wires": [
[
"37a495c063566b97"
]
]
},
{
"id": "37a495c063566b97",
"type": "function",
"z": "fbda6ab16491b918",
"g": "40b2e704eefd62e1",
"name": "Format Pastebin Call",
"func": "\nlet payload = {\n \"api_paste_code\": encodeURIComponent(JSON.stringify(msg.payload)),\n \"api_paste_name\": encodeURIComponent(\"bambu_{PRINTER_NAME}_bedmesh.txt\"),\n \"api_paste_expire_date\": \"1M\",\n \"api_option\":\"paste\",\n \"api_paste_private\":\"1\"\n};\n\nlet url = \"https://pastebin.com/api/api_post.php\"\nlet data = \"\";\n\nfor(var key of Object.keys(payload)) {\n data = data + \"&\" + key +\"=\"+payload[key];\n}\ndata += \"&api_dev_key=\" + \"{PASTEBIN_KEY}\";\nmsg.payload = data;\nmsg.url = url;\n\nnode.send(msg);\n",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 2320,
"y": 2160,
"wires": [
[
"91a9f3a785e5167e"
]
]
},
{
"id": "91a9f3a785e5167e",
"type": "http request",
"z": "fbda6ab16491b918",
"g": "40b2e704eefd62e1",
"name": "",
"method": "POST",
"ret": "txt",
"paytoqs": "ignore",
"url": "",
"tls": "",
"persist": false,
"proxy": "",
"insecureHTTPParser": false,
"authType": "",
"senderr": false,
"headers": [
{
"keyType": "other",
"keyValue": "Content-type",
"valueType": "other",
"valueValue": "application/x-www-form-urlencoded"
}
],
"x": 2310,
"y": 2200,
"wires": [
[
"36fdeabb54b38c86"
]
]
},
{
"id": "36fdeabb54b38c86",
"type": "function",
"z": "fbda6ab16491b918",
"g": "40b2e704eefd62e1",
"name": "Handle Response",
"func": "if (msg.payload != undefined) {\n if (msg.payload.includes(\"Bad API\")) {\n msg.payload = \"Check MQTT\";\n }\n msg.payload = msg.payload.replace(\".com\", \".com/raw\")\n msg.topic = \"bed_mesh_data\";\n node.send(msg);\n}",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 2350,
"y": 2240,
"wires": [
[
"6c9219a2f8830bd1"
]
]
},
{
"id": "8c3888bbf1ce213c",
"type": "function",
"z": "fbda6ab16491b918",
"g": "40b2e704eefd62e1",
"name": "Set None",
"func": "msg.topic = \"bed_mesh_data\";\nmsg.payload = \"None\";\nmsg.raw = [];\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 2220,
"y": 1920,
"wires": [
[
"b605d208757fde56"
]
]
},
{
"id": "b605d208757fde56",
"type": "delay",
"z": "fbda6ab16491b918",
"g": "40b2e704eefd62e1",
"name": "",
"pauseType": "delay",
"timeout": "2",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"x": 2340,
"y": 1880,
"wires": [
[
"cc539923f0b07cb5"
]
]
},
{
"id": "cc539923f0b07cb5",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "40b2e704eefd62e1",
"x": 2480,
"y": 1920,
"wires": [
[
"88c5fd6ecd7e759c",
"8f497caa1a935bbc"
]
]
},
{
"id": "1e2b1247f1d0c0e1",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "40b2e704eefd62e1",
"x": 2680,
"y": 2200,
"wires": [
[
"8cbcc2518bb88578"
]
]
},
{
"id": "c154af220552f516",
"type": "comment",
"z": "fbda6ab16491b918",
"g": "40b2e704eefd62e1",
"name": "Bed Mesh Flow: REV 49",
"info": "Rev 49: 2023-05-05\n- Initial Creation",
"x": 1850,
"y": 1880,
"wires": []
},
{
"id": "29b479f5aa4d6618",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "40b2e704eefd62e1",
"name": "",
"property": "abl",
"propertyType": "flow",
"rules": [
{
"t": "neq",
"v": "[]",
"vt": "jsonata"
}
],
"checkall": "true",
"repair": false,
"outputs": 1,
"x": 2230,
"y": 2040,
"wires": [
[
"320a9e3ba5045959"
]
]
},
{
"id": "4a5fb4819bb0abdd",
"type": "delay",
"z": "fbda6ab16491b918",
"g": "40b2e704eefd62e1",
"name": "",
"pauseType": "delay",
"timeout": "10",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"x": 2360,
"y": 1960,
"wires": [
[
"24cc9339f7d7c497"
]
]
},
{
"id": "6c9219a2f8830bd1",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "40b2e704eefd62e1",
"x": 2460,
"y": 1940,
"wires": [
[
"cc539923f0b07cb5",
"4a5fb4819bb0abdd"
]
]
}
]
[
{
"id": "296274a0d2a6c675",
"type": "group",
"z": "fbda6ab16491b918",
"name": "Bambu MQTT Relay",
"style": {
"stroke": "#92d04f",
"label": true,
"color": "#92d04f"
},
"nodes": [
"b1c1923cb89b667b",
"7c5bb5efa50cfa5b",
"69b4c2a7d4558125",
"a365818fb4a53f52",
"1389ca15cce63bbb",
"9737da24b3e03e14",
"9b44ae9e961cc5e3",
"1f20b9de36cc424b",
"7260cf57c3edbd49",
"7c6b4583707029ea",
"8d2a544a9c61d783",
"d5e7799961b2eb4f",
"ff09ef39735c8dd8",
"07ff86f3cd404e2d",
"3412b5c7efd1d41e",
"098967fde25793c1",
"2d01d38e6dd73736",
"9d95b756f4601713",
"5774338c2d9e049b",
"1f0305e93eed961a",
"2a60f3818c07cead",
"bf872cba7b8d4a63",
"2f77cb6feca03746",
"69cba2483fe68056",
"17945f4d7962a94a",
"a0317478d3f43ecf",
"8171a948ce6a2ae7",
"472a15482a731de8",
"86e9caa98fa51352",
"41797ced12627146",
"2ce84ba9618b908d",
"b2881b8ed28a467c",
"96b92ea713edd221",
"f7de3b0a2a7c5661",
"8399cea217e486b9",
"f0bcc0434d35f8db",
"1db470110f18fab6",
"2a0268a55eadf72f",
"c93c3bb2cc88b9dc",
"d8d2dad22b354fdf",
"e9f7f1de7feb3909",
"dce813c208a9da90",
"ab7f1b7beb3a2f80",
"080745c0307e0218",
"8a61805ce8145c12",
"eec5b5dc9281ea93",
"6a13ae7af77d563d",
"5c4b13a29c630b8c",
"b5232b827fbef671",
"4a696bec52ae5acb",
"962c0c56346e023a",
"db012956ddb6c2af",
"ad4f3f980f172128",
"ecf4cb43eed20ca0",
"b3ee63836831ea89",
"b5fb8a1a65b4686b",
"682e4da1ee0769d4",
"e98417ec17a23249",
"135e57a801b6e9bf",
"7f4faea318d59bed",
"9a2aaf740774a256",
"f844bda465c93ddd",
"e34f034bed456673",
"dba47578907a6d23",
"735003dd7602e7dc",
"c40efe7b1b254622",
"b34fe28bd6f1cf0b",
"883a607fd81a0e23",
"67aa1b3a6a0ac3d7",
"c868c39bb6549391",
"af54a0a5940dd334",
"ca1821a15d5fe203",
"6db1d3c86598f8a4",
"0c9c48807302abbe",
"7cbd22af688976aa",
"12d493bc4868cb6b",
"6526126078390137",
"f6805ea36226a930",
"c1bc72e5401a7523",
"97e117e5e3b6b2ac",
"dbd5442f44b5d5eb",
"574efe9bef59bfe8",
"dff0a7bcab99db34",
"17dc50ac469fdac7",
"51c3cfdad1576d27",
"2dcd252aec842a4b",
"0539d7216c7abb63",
"dae563cbc58f46bd",
"1105b8629aa017ee",
"73ce7dbb92cee565",
"4293665f8ddd9f37",
"2fe75ce36321f506",
"a1c7a965b0d664fe",
"3907f3b052894ad1",
"a4d29254d471acd7",
"1288bcdd3d2bc704",
"d20b02ea37dbdddf",
"8959434b99b38bdd",
"7ba7e522b0b73697",
"ebe6d4b6979d7c94",
"804bf6ba99e0a70d",
"1186527cf1f7ec0e",
"891080cdc3c0148e",
"2f43a94e4c1c67b7",
"ceef34fb1803fabb",
"3e88e7f16efe9866",
"9693988d17d6b075",
"7ec4f5ae5c5f4a57",
"c912472120552915",
"9271157140e4588a",
"11d9daa56bb64de3",
"cdbbe3908ea0d90e",
"214dc07ca387eb0a",
"e4c85d8612f4d7d8",
"147574759061cf4e",
"ba2e021eef1322ea",
"17b0dcf3695419d6",
"193d411066edd78a",
"cbf991bc44588b46",
"15f1d2104c14b32d",
"236eb62e785fa16a",
"ec6f548a5bc948b2",
"3b9a660c508f1cb6",
"3a1ed497179905d8",
"bbb04109ed20f916",
"e556e5d4352c614c",
"8040953d45a1e453",
"aab0848e64d380c3",
"a57684202aa2160e",
"c8e2eab0fad37985",
"345a439e1ca993a9",
"dbc27a9fddc3334e",
"3514fee9e8cb92a1",
"2250e65775ee5fba",
"0db02154b69078d5",
"e59529e8f4f2b4d7",
"bcf32534e23d8cb5",
"62ac383912a1df6b",
"edfd9d58baed5c0e",
"90ec5d0b9ffa32e4",
"df64a614382d6055",
"9f88ad5505fac7cf",
"5c7aac3c3657ba24",
"05f30349cf1717a7",
"b2e7df90b8407c7a",
"fc410f217da7eda4",
"70d2024d191a082e",
"66a2cbf9f289b7aa",
"f1a328459d02685b",
"248ebd30cb6cf901",
"92a884a3331bfa4b",
"5cd82175da584146",
"d944c995cf7771e0",
"8eb8d0318afc5c0b",
"6835f39fb902578a",
"9362a1b7e3670507",
"0a5d92c3648ea7af",
"92b557ed537a1451",
"dcf228c59349178a",
"128d03867a7d32ad",
"05e6995783570ac3",
"8f276707783e36e0",
"b04f934b4958c998",
"a6a549b513fe916b",
"0e9d8e65b9383827",
"e509c1902d9bb186",
"71f3cd131ac47b5f",
"f9ebb81f5664f91d",
"4521e494acb429e6",
"51e0ffef53d5bc20",
"b4eef9bbefd37b47",
"956693cec86ba0b4",
"8548eff7812ded96",
"58c7d66c6f3c35c4",
"1e92fa493eba35e5",
"07466678a4986a7a",
"96906ffafad503eb",
"4c8011bd5cb181a7",
"c5cc9910c88c94d9",
"9ea2ae26de45d301",
"b8012fa88ed7a0a8",
"d7d2f90f2ea888c7",
"30917db9b244627a",
"ee27856bdf0642fc"
],
"x": 14,
"y": 19,
"w": 2232,
"h": 1382
},
{
"id": "b1c1923cb89b667b",
"type": "mqtt in",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Bambu X1C {PRINTER_NAME}",
"topic": "",
"qos": "2",
"datatype": "json",
"broker": "{GENERATED_PRINTER_MQTT_ID}",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 1,
"x": 170,
"y": 260,
"wires": [
[
"69b4c2a7d4558125"
]
]
},
{
"id": "7c5bb5efa50cfa5b",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Inject Machine Details",
"func": "let machine_name = \"{PRINTER_NAME}\";\nlet machine_serial = \"{PRINTER_SERIAL}\";\nlet manufacturer = \"Bambu Labs\";\nlet model = \"X1 Carbon\"\n\nlet camera_stream_url = \"{STREAM_URL}\";\nlet snapshot_url = \"{SNAPSHOT_URL}\";\n\nif(msg.payload.mc_print != undefined) {\n msg.payload.mc_print.machine_name = machine_name;\n msg.payload.mc_print.machine_serial = machine_serial;\n msg.payload.mc_print.manufacturer = manufacturer;\n if(msg.payload.mc_print.param.includes(\"[AMS]\")) {\n msg.payload.mc_print.model = \"AMS\";\n }\n else {\n msg.payload.mc_print.model = model;\n }\n}\n\nif (msg.payload.print != undefined) {\n msg.payload.print.machine_name = machine_name;\n msg.payload.print.machine_serial = machine_serial;\n msg.machine_serial = machine_serial;\n msg.payload.print.manufacturer = manufacturer;\n msg.payload.print.model = model;\n\n if (msg.payload.print.ams !== undefined) {\n for (var ams of msg.payload.print.ams.ams) {\n ams.printer_name = machine_name\n ams.printer_serial = machine_serial\n }\n }\n msg.payload.print.status = \"online\";\n msg.payload.print.reset_filter = \"\";\n msg.payload.print.pause_print = \"\";\n msg.payload.print.resume_print = \"\";\n msg.payload.print.stop_print = \"\";\n msg.payload.print.force_update = \"\";\n msg.payload.print.logo_light_on = \"\";\n msg.payload.print.logo_light_off = \"\";\n msg.payload.print.nozzle_light_on = \"\";\n msg.payload.print.nozzle_light_off = \"\";\n\n msg.payload.print.set_bed_temp = \"\";\n msg.payload.print.set_nozzle_temp = \"\";\n\n msg.payload.print.print_preview = \"\";\n msg.payload.print.plate_type = \"\";\n\n msg.payload.print.clear_external_spool = \"\";\n msg.payload.print.last_calibrated_pa = \"\";\n msg.payload.print.unload_filament = \"\";\n\n if(snapshot_url != undefined && snapshot_url != \"\" && snapshot_url != \"{\" + \"SNAPSHOT_URL\" + \"}\") {\n msg.payload.print.snapshot_url = snapshot_url;\n }\n\n if (camera_stream_url != undefined && camera_stream_url != \"\" && camera_stream_url != \"{\" + \"STREAM_URL\" + \"}\") {\n msg.payload.print.camera_stream_url = camera_stream_url;\n }\n\n}\n\n\nif (msg.payload.info != undefined) {\n msg.printer_name = machine_name;\n msg.machine_serial = machine_serial;\n msg.manufacturer = manufacturer;\n msg.model = model;\n}\n\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 160,
"y": 300,
"wires": [
[
"ebe6d4b6979d7c94"
]
]
},
{
"id": "69b4c2a7d4558125",
"type": "json",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"property": "payload.print",
"action": "obj",
"pretty": false,
"x": 370,
"y": 260,
"wires": [
[
"7c5bb5efa50cfa5b"
]
]
},
{
"id": "a365818fb4a53f52",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"property": "payload",
"propertyType": "msg",
"rules": [
{
"t": "hask",
"v": "info",
"vt": "str"
},
{
"t": "hask",
"v": "mc_print",
"vt": "str"
},
{
"t": "hask",
"v": "print",
"vt": "str"
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 4,
"x": 610,
"y": 300,
"wires": [
[
"97e117e5e3b6b2ac"
],
[
"883a607fd81a0e23"
],
[
"8a61805ce8145c12"
],
[]
]
},
{
"id": "1389ca15cce63bbb",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Known Filament Translator",
"func": "// Bambu spools are not needed for translation if they have the rfid tags\n// but this can be used to overwrite them for HA displaying only\n// This only overwrites the tray_type and tray_sub_brands, if you want other fields overwritten you can add them\n// e.g. tray_diameter, tray_weight, temps etc\n\nvar PolyLite_PLA = {\n \"tray_info_idx\": \"GFL00\", \n \"tray_type\": \"PLA\",\n \"tray_sub_brands\": \"PolyLite PLA\"\n}\n\nvar PolyTerra_PLA = {\n \"tray_info_idx\": \"GFL01\",\n \"tray_type\": \"PLA\",\n \"tray_sub_brands\": \"PolyTerra PLA\"\n}\n\nvar Bambu_ABS = {\n \"tray_info_idx\": \"GFB00\",\n \"tray_type\": \"ABS\"\n}\n\nvar Bambu_PACF = {\n \"tray_info_idx\": \"GFN03\",\n \"tray_type\": \"PA-CF\"\n}\n\nvar Bambu_PC = {\n \"tray_info_idx\": \"GFC00\",\n \"tray_type\": \"PC\"\n}\n\nvar Bambu_PLA_Basic = {\n \"tray_info_idx\": \"GFA00\",\n \"tray_type\": \"PLA\",\n \"tray_sub_brands\": \"PLA Basic\"\n}\nvar Bambu_PLA_Matte = {\n \"tray_info_idx\": \"GFA01\",\n \"tray_type\": \"PLA\",\n \"tray_sub_brands\": \"PLA Matte\"\n}\n\nvar Support_G = {\n \"tray_info_idx\": \"GFS01\",\n \"tray_type\": \"Support\",\n \"tray_sub_brands\": \"Support G\"\n}\n\nvar Support_W = {\n \"tray_info_idx\": \"GFS00\",\n \"tray_type\": \"Support\",\n \"tray_sub_brands\": \"Support W\"\n}\n\nvar Bambu_TPU_95A = {\n \"tray_info_idx\": \"GFU01\",\n \"tray_type\": \"TPU\",\n \"tray_sub_brands\": \"TPU 95A\"\n}\n\nvar Generic_ABS = {\n \"tray_info_idx\": \"GFB99\",\n \"tray_type\": \"ABS\",\n \"tray_sub_brands\": \"ABS\"\n}\n\nvar Generic_ASA = {\n \"tray_info_idx\": \"GFB98\",\n \"tray_type\": \"ASA\",\n \"tray_sub_brands\": \"ASA\"\n}\n\nvar Generic_PA = {\n \"tray_info_idx\": \"GFN99\",\n \"tray_type\": \"PA\",\n \"tray_sub_brands\": \"PA\"\n}\n\nvar Generic_PACF = {\n \"tray_info_idx\": \"GFN98\",\n \"tray_type\": \"PA-CF\",\n \"tray_sub_brands\": \"PA-CF\"\n}\n\nvar Generic_PC = {\n \"tray_info_idx\": \"GFC99\",\n \"tray_type\": \"PC\",\n \"tray_sub_brands\": \"PC\"\n} \n\nvar Generic_PETG = {\n \"tray_info_idx\": \"GFG99\",\n \"tray_type\": \"PETG\",\n \"tray_sub_brands\": \"PETG\"\n}\nvar Generic_PLA = {\n \"tray_info_idx\": \"GFL99\",\n \"tray_type\": \"PLA\",\n \"tray_sub_brands\": \"PLA\"\n}\nvar Generic_PLACF = {\n \"tray_info_idx\": \"GFL98\",\n \"tray_type\": \"PLA-CF\",\n \"tray_sub_brands\": \"PLA-CF\"\n}\nvar Generic_PVA = {\n \"tray_info_idx\": \"GFS99\",\n \"tray_type\": \"PVA\",\n \"tray_sub_brands\": \"PVA\"\n}\nvar Generic_TPU = {\n \"tray_info_idx\": \"GFU99\",\n \"tray_type\": \"TPU\",\n \"tray_sub_brands\": \"TPU\"\n}\n\nvar Bambu_PETCF = {\n \"tray_info_idx\": \"GFT00\",\n \"tray_type\": \"PET-CF\"\n}\n\nvar Bambu_PLA_Impact = {\n \"tray_info_idx\": \"GFA03\",\n \"tray_type\": \"PLA\",\n \"tray_sub_brands\": \"PLA Impact\"\n}\n\nvar Bambu_PLA_Metal = {\n \"tray_info_idx\": \"GFA02\",\n \"tray_type\": \"PLA\",\n \"tray_sub_brands\": \"PLA Metal\"\n}\n\nvar filament_library = {\n \"GFU99\": Generic_TPU,\n \"GFS99\": Generic_PVA,\n \"GFL98\": Generic_PLACF,\n \"GFL99\": Generic_PLA,\n \"GFG99\": Generic_PETG,\n \"GFC99\": Generic_PC,\n \"GFN98\": Generic_PACF,\n \"GFN99\": Generic_PA,\n \"GFB98\": Generic_ASA,\n \"GFB99\": Generic_ABS,\n \"GFU01\": Bambu_TPU_95A,\n \"GFS00\": Support_W,\n \"GFS01\": Support_G,\n \"GFA01\": Bambu_PLA_Matte,\n \"GFA00\": Bambu_PLA_Basic,\n \"GFC00\": Bambu_PC,\n \"GFN03\": Bambu_PACF,\n \"GFB00\": Bambu_ABS,\n \"GFL01\": PolyTerra_PLA,\n \"GFL00\": PolyLite_PLA\n}\n\nif (msg.payload.print.ams !== undefined) {\n for (var ams of msg.payload.print.ams.ams) {\n for (var tray of ams.tray) {\n if (tray.tray_info_idx !== undefined && tray.tray_info_idx !== \"\") {\n if(filament_library.hasOwnProperty(tray.tray_info_idx)) {\n var match = filament_library[tray.tray_info_idx];\n tray.tray_type = match.tray_type;\n tray.tray_sub_brands = match.tray_sub_brands;\n if (tray.tray_diameter == \"0.00\") {\n tray.tray_diameter = \"1.75\";\n }\n }\n }\n }\n }\n}\nif(msg.payload.print.vt_tray != undefined) {\n if (msg.payload.print.vt_tray.tray_info_idx != undefined) {\n if (filament_library.hasOwnProperty(msg.payload.print.vt_tray.tray_info_idx)) {\n var match = filament_library[msg.payload.print.vt_tray.tray_info_idx];\n msg.payload.print.vt_tray.tray_type = match.tray_type;\n msg.payload.print.vt_tray.tray_sub_brands = match.tray_sub_brands;\n if (msg.payload.print.vt_tray.tray_diameter == \"0.00\") {\n msg.payload.print.vt_tray.tray_diameter = \"1.75\";\n }\n }\n }\n}\n\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 680,
"y": 360,
"wires": [
[
"9737da24b3e03e14"
]
]
},
{
"id": "9737da24b3e03e14",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Fan Speed Translator",
"func": "function parsePercent(speed) {\n let percent = (parseInt(speed) / 15) * 100;\n return Math.ceil(percent / 10) * 10;\n}\n\n// Overwrite\nif(msg.payload.print.big_fan1_speed != undefined) {\n msg.payload.print.big_fan1_speed = parsePercent(msg.payload.print.big_fan1_speed);\n}\nif (msg.payload.print.big_fan2_speed != undefined) {\n msg.payload.print.big_fan2_speed = parsePercent(msg.payload.print.big_fan2_speed);\n}\n\nif (msg.payload.print.heatbreak_fan_speed != undefined) {\n msg.payload.print.heatbreak_fan_speed = parsePercent(msg.payload.print.heatbreak_fan_speed);\n}\n\nif (msg.payload.print.cooling_fan_speed != undefined) {\n msg.payload.print.cooling_fan_speed = parsePercent(msg.payload.print.cooling_fan_speed);\n}\n\nnode.send(msg)",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 660,
"y": 400,
"wires": [
[
"9b44ae9e961cc5e3"
]
]
},
{
"id": "9b44ae9e961cc5e3",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Set Tray Statuses",
"func": "if(msg.payload.print != undefined) { \n msg.payload.print.filament = \"None\";\n}\nlet ams_in_use = false;\nlet virtual_in_use = false;\nif (msg.payload.print.ams != undefined && msg.payload.print.ams.tray_now !== undefined) {\n for (var ams of msg.payload.print.ams.ams) {\n for (var tray of ams.tray) {\n if (tray.tray_type == undefined || tray.tray_type == \"\") {\n tray.tray_type = \"Empty\";\n tray.tray_color = \"#808080\";\n } \n else {\n tray.tray_color = \"#\" + tray.tray_color;\n }\n\n tray.in_use = false;\n\n var id = parseInt(tray.id);\n var used_id = parseInt(msg.payload.print.ams.tray_now);\n\n if (used_id == (id + 4* parseInt(ams.id))) {\n tray.in_use = true;\n ams_in_use = true;\n virtual_in_use = false;\n if(tray.tray_type != \"Empty\") {\n msg.payload.print.filament = tray.tray_type;\n }\n }\n else if(used_id == 254) {\n ams_in_use = false;\n virtual_in_use = true;\n }\n\n tray.ams_id = ams.id;\n }\n }\n}\nif(msg.payload.print.vt_tray != undefined) {\n msg.payload.print.filament = \"Unknown\";\n if(msg.payload.print.vt_tray.tray_type != undefined) {\n msg.payload.print.vt_tray.type = msg.payload.print.vt_tray.tray_type;\n delete msg.payload.print.vt_tray.tray_type;\n msg.payload.print.filament = msg.payload.print.vt_tray.type;\n if (msg.payload.print.vt_tray.tray_color != undefined) {\n msg.payload.print.vt_tray.color = msg.payload.print.vt_tray.tray_color;\n delete msg.payload.print.vt_tray.tray_color;\n }\n if (msg.payload.print.vt_tray.color == undefined || msg.payload.print.vt_tray.color == \"\") {\n msg.payload.print.vt_tray.color = \"#808080\";\n }\n if (msg.payload.print.vt_tray.type == undefined || msg.payload.print.vt_tray.type == \"\") {\n msg.payload.print.vt_tray.type = \"Empty\";\n msg.payload.print.vt_tray.color = \"#808080\";\n }\n\n msg.payload.print.filament = msg.payload.print.vt_tray.type;\n if(msg.payload.print.filament == \"Empty\") {\n msg.payload.print.filament = \"Unknown\";\n }\n\n if (msg.payload.print.vt_tray.color != undefined && !msg.payload.print.vt_tray.color.startsWith(\"#\")) {\n msg.payload.print.vt_tray.color = \"#\" + msg.payload.print.vt_tray.color;\n }\n }\n if(!ams_in_use && virtual_in_use) {\n msg.payload.print.vt_tray.in_use = true;\n }\n\n}\n\nif(msg.payload.print.filament != undefined && msg.payload.print.filament == \"Unknown\") {\n delete msg.payload.print.filament;\n}\nif(msg.payload.print.gcode_state != undefined && \n msg.payload.print.gcode_state == \"RUNNING\" && \n msg.payload.print.filament != undefined\n && msg.payload.print.filament == \"None\") {\n delete msg.payload.print.filament;\n //msg.payload.print.filament = \"Unknown\";\n}\nnode.send(msg);\n",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 650,
"y": 440,
"wires": [
[
"1f20b9de36cc424b"
]
]
},
{
"id": "1f20b9de36cc424b",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Organize Lights",
"func": "var lights = {};\nif (msg.payload.print.lights_report !== undefined) {\n for (var element of msg.payload.print.lights_report) {\n lights[element.node] = element.mode;\n }\n msg.payload.print.lights = lights\n}\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 640,
"y": 480,
"wires": [
[
"7260cf57c3edbd49"
]
]
},
{
"id": "7260cf57c3edbd49",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Stage Parser",
"func": "\nfunction parseAction(actionId) {\n if(actionId === undefined) {\n return \"\";\n }\n switch (actionId) {\n case -2:\n return \"Offline\";\n case -1:\n return \"Idle\";\n case 0:\n return \"Printing\";\n case 1:\n return \"Auto bed leveling\";\n case 2:\n return \"Heatbed preheating\";\n case 3:\n return \"Sweeping XY mech mode\";\n case 4:\n return \"Changing filament\";\n case 5:\n return \"M400 pause\";\n case 6:\n return \"Paused due to filament runout\";\n case 7:\n return \"Heating hotend\";\n case 8:\n return \"Calibrating extrusion\";\n case 9:\n return \"Scanning bed surface\";\n case 10:\n return \"Inspecting first layer\";\n case 11:\n return \"Identifying build plate type\";\n case 12:\n return \"Calibrating Micro Lidar\";\n case 13:\n return \"Homing toolhead\";\n case 14:\n return \"Cleaning nozzle tip\";\n case 15:\n return \"Checking extruder temperature\";\n case 16:\n return \"Printing was paused by the user\";\n case 17:\n return \"Pause of front cover falling\";\n case 18:\n return \"Calibrating the micro lidar\";\n case 19:\n return \"Calibrating extrusion flow\";\n case 20:\n return \"Paused due to nozzle temperature malfunction\";\n case 21:\n return \"Paused due to heat bed temperature malfunction\";\n default:\n return actionId.toString()\n }\n}\n\nif(msg.payload.print.stg_cur != undefined){\n var current_action = parseAction(msg.payload.print.stg_cur);\n msg.payload.print.stg_cur = current_action;\n}\nvar translated_stages = [];\nif(msg.payload.print.stg != undefined) {\n for (var stage of msg.payload.print.stg) {\n translated_stages.push(parseAction(stage))\n }\n msg.payload.print.stg = translated_stages;\n}\n\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 630,
"y": 520,
"wires": [
[
"a1c7a965b0d664fe"
]
]
},
{
"id": "7c6b4583707029ea",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Translate X1C Speed Profile",
"func": "var spd = {}\nif(msg.payload.print.spd_mag != undefined) {\n spd.modifier = msg.payload.print.spd_mag;\n}\nif (msg.payload.print.spd_lvl !== undefined) {\n spd.level = msg.payload.print.spd_lvl;\n switch (msg.payload.print.spd_lvl) {\n case 1:\n spd.profile = \"Silent\";\n break;\n case 2:\n spd.profile = \"Standard\";\n break;\n case 3:\n spd.profile = \"Sport\";\n break;\n case 4:\n spd.profile = \"Ludicrous\";\n break;\n default:\n spd.profile = \"Undefined\";\n break;\n }\n if (msg.payload.print.spd != undefined) {\n delete msg.payload.print.spd;\n }\n msg.payload.print.speed = spd;\n}\n\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 680,
"y": 560,
"wires": [
[
"2f43a94e4c1c67b7"
]
]
},
{
"id": "8d2a544a9c61d783",
"type": "split",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"splt": "\\n",
"spltType": "str",
"arraySplt": 1,
"arraySpltType": "len",
"stream": false,
"addname": "topic",
"x": 810,
"y": 600,
"wires": [
[
"d5e7799961b2eb4f"
]
]
},
{
"id": "d5e7799961b2eb4f",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"property": "topic",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "printer",
"vt": "str"
},
{
"t": "eq",
"v": "ams",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 2,
"x": 930,
"y": 600,
"wires": [
[
"db012956ddb6c2af"
],
[
"ceef34fb1803fabb"
]
]
},
{
"id": "ff09ef39735c8dd8",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "AMS Config",
"func": "let data = {};\nlet payload = {};\nlet device = {};\n\nvar printer_name = \"X1C_\";\nprinter_name = printer_name + msg.machine_name.match(/AMS_\\d+_(.*)/)[1];\n\n// Filter UoM from payload\nif (msg.topic == \"wifi_signal\")\n msg.payload = msg.payload.match(/^-?\\d+/)[0];\n\n// Inject config\nif (msg.topic.match(/temper/)) {\n msg.device_class = \"temperature\";\n}\nif (msg.topic.match(/temp/)) {\n msg.device_class = \"temperature\";\n}\nif (msg.topic == \"wifi_signal\") {\n msg.device_class = \"signal_strength\"\n msg.unit_of_measurement = \"dBm\";\n}\n\nif(msg.topic == \"humidity\") {\n msg.device_class = \"humidity\";\n msg.unit_of_measurement = \"%\";\n}\n\nif(msg.topic == \"HW_version\") {\n device.hw_version = msg.payload;\n}\nif(msg.topic == \"SW_version\") {\n device.sw_version = msg.payload;\n}\n\n\nfunction getFriendlyName(str) {\n var i, word = str.split('_');\n for (i = 0; i < word.length; i++) {\n word[i] = word[i].charAt(0).toUpperCase() + word[i].slice(1);\n }\n return word.join(' ');\n}\n\nlet base_topic = \"homeassistant/sensor/\" + msg.machine_name + \"/\" + msg.topic;\ndata.topic = base_topic + \"/config\";\npayload.name = getFriendlyName(msg.topic);\n\ndevice.identifiers = [];\ndevice.identifiers[0] = msg.machine_name;\n\nif (msg.topic == \"serial_number\") {\n device.identifiers[1] = msg.payload;\n}\n\ndevice.manufacturer = \"Bambu Labs\";\ndevice.model = \"AMS\";\ndevice.name = msg.machine_name;\ndevice.via_device = printer_name;\n\n\npayload.device = device;\npayload.unique_id = msg.machine_name + \"_\" + msg.topic;\npayload.object_id = payload.unique_id;\n\n//payload.force_update = true;\n\nif (!msg.topic.includes(\"tray\")){\n //payload.expire_after = 3600;\n}\nelse {\n payload.icon = \"mdi:printer-3d-nozzle\";\n}\n\nif(msg.topic.match(/serial/)) {\n payload.icon = \"mdi:barcode\";\n}\nif (msg.topic == \"printer_name\") {\n payload.icon = \"mdi:printer-3d\";\n}\nif (msg.device_class != undefined)\n payload.device_class = msg.device_class;\n\nif (msg.unit_of_measurement != undefined)\n payload.unit_of_measurement = msg.unit_of_measurement;\n\nif (payload.device_class == \"temperature\") {\n payload.unit_of_measurement = \"°C\";\n payload.temperature_unit = \"°C\";\n}\n\nif (!msg.topic.includes(\"tray\")) {\n payload.availability_topic = \"homeassistant/\" + \"sensor\" + \"/\" + printer_name + \"/\" + \"status\" + \"/state\";\n}\n\npayload.state_topic = base_topic + \"/state\";\npayload.json_attributes_topic = base_topic + \"/attr\";\ndata.payload = payload;\n\ndata.qos = 1;\ndata.retain = true;\nnode.send(data);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1210,
"y": 840,
"wires": [
[
"b3ee63836831ea89"
]
]
},
{
"id": "07ff86f3cd404e2d",
"type": "split",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"splt": "\\n",
"spltType": "str",
"arraySplt": 1,
"arraySpltType": "len",
"stream": false,
"addname": "topic",
"x": 790,
"y": 640,
"wires": [
[
"3412b5c7efd1d41e"
]
]
},
{
"id": "3412b5c7efd1d41e",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "ams",
"func": "msg.topic = \"AMS\";//_\" + msg.payload.id;\n\nmsg.machine_name = msg.topic + \"_\" + msg.payload.id + \"_\" + msg.payload.printer_name;\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 910,
"y": 640,
"wires": [
[
"3e88e7f16efe9866"
]
]
},
{
"id": "098967fde25793c1",
"type": "change",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Set End Time Init",
"rules": [
{
"t": "set",
"p": "payload.gcode_end_time",
"pt": "msg",
"to": "",
"tot": "date"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 1250,
"y": 260,
"wires": [
[
"2d01d38e6dd73736"
]
]
},
{
"id": "2d01d38e6dd73736",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Set EndTime",
"func": "if(msg.payload.gcode_start_time == undefined) {\n if(msg.payload.gcode_end_time != undefined) {\n delete msg.payload.gcode_end_time;\n }\n node.send(msg);\n}\nelse {\n if (msg.payload.gcode_start_time !== \"N/A\" && msg.payload.gcode_end_time !== undefined && msg.payload.gcode_end_time != \"N/A\"\n && msg.payload.mc_remaining_time != undefined) {\n var endTime = msg.payload.gcode_end_time + ((parseInt(msg.payload.mc_remaining_time) * 60) * 1000);\n endTime = Math.round(endTime / 60000) * 60000;\n var startSeconds = msg.payload.gcode_start_epoch.toString().slice(0,-5);\n endTime = endTime + parseInt(startSeconds);\n msg.payload.gcode_end_time = endTime;\n msg.payload.gcode_start_time = parseInt(msg.payload.gcode_start_time);\n node.send(msg);\n }\n else if (msg.payload.gcode_end_time == \"N/A\" || msg.payload.gcode_start_Time == \"N/A\") {\n msg.payload.gcode_start_time = \"N/A\";\n msg.payload.gcode_end_time = \"N/A\";\n node.send(msg);\n }\n\n if (msg.payload.gcode_start_time == \"N/A\" || msg.payload.mc_remaining_time == undefined) {\n msg.payload.gcode_end_time = \"N/A\";\n }\n else {\n node.send(msg);\n }\n}",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1250,
"y": 300,
"wires": [
[
"9d95b756f4601713"
]
]
},
{
"id": "9d95b756f4601713",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"property": "payload.gcode_end_time",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "N/A",
"vt": "str"
},
{
"t": "null"
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 3,
"x": 1390,
"y": 300,
"wires": [
[
"ad4f3f980f172128"
],
[
"11d9daa56bb64de3"
],
[
"af54a0a5940dd334"
]
]
},
{
"id": "5774338c2d9e049b",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"property": "payload.gcode_start_time",
"propertyType": "msg",
"rules": [
{
"t": "neq",
"v": "N/A",
"vt": "str"
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 2,
"x": 1070,
"y": 260,
"wires": [
[
"098967fde25793c1"
],
[
"2d01d38e6dd73736"
]
]
},
{
"id": "1f0305e93eed961a",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "AMS State",
"func": "// Filter UoM from payload\nif (msg.topic == \"wifi_signal\")\n msg.payload = msg.payload.match(/^-?\\d+/)[0];\nif (msg.topic.match(/tray_\\d+/)) {\n var oldTopic = msg.topic;\n msg.topic = \"homeassistant/sensor/\" + msg.machine_name + \"/\" + msg.topic + \"/attr\";\n node.send(msg);\n msg.topic = oldTopic;\n msg.payload = msg.payload.type;\n}\n\nmsg.topic = \"homeassistant/sensor/\" + msg.machine_name + \"/\" + msg.topic + \"/state\";\n\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1210,
"y": 880,
"wires": [
[
"b3ee63836831ea89"
]
]
},
{
"id": "2a60f3818c07cead",
"type": "split",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"splt": "\\n",
"spltType": "str",
"arraySplt": 1,
"arraySpltType": "len",
"stream": false,
"addname": "topic",
"x": 630,
"y": 780,
"wires": [
[
"bf872cba7b8d4a63"
]
]
},
{
"id": "bf872cba7b8d4a63",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"property": "topic",
"propertyType": "msg",
"rules": [
{
"t": "neq",
"v": "tray",
"vt": "str"
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 2,
"x": 750,
"y": 780,
"wires": [
[
"735003dd7602e7dc"
],
[
"2f77cb6feca03746"
]
]
},
{
"id": "2f77cb6feca03746",
"type": "split",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"splt": "\\n",
"spltType": "str",
"arraySplt": 1,
"arraySpltType": "len",
"stream": false,
"addname": "topic",
"x": 630,
"y": 820,
"wires": [
[
"69cba2483fe68056"
]
]
},
{
"id": "69cba2483fe68056",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "tray",
"func": "msg.topic = msg.topic + \"_\" + msg.payload.id;\nnode.send(msg);\n",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 750,
"y": 820,
"wires": [
[
"080745c0307e0218"
]
]
},
{
"id": "17945f4d7962a94a",
"type": "mqtt out",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Home Assistant",
"topic": "",
"qos": "",
"retain": "",
"respTopic": "",
"contentType": "",
"userProps": "",
"correl": "",
"expiry": "",
"broker": "489094618c340eef",
"x": 2140,
"y": 860,
"wires": []
},
{
"id": "a0317478d3f43ecf",
"type": "change",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Set Status",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "online",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 930,
"y": 720,
"wires": [
[
"b5fb8a1a65b4686b"
]
]
},
{
"id": "8171a948ce6a2ae7",
"type": "comment",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "AMS",
"info": "AMS Split",
"x": 610,
"y": 680,
"wires": []
},
{
"id": "472a15482a731de8",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Printer Config",
"func": "let data = {};\nlet payload = {};\nlet device = {};\n\nif(msg.payload == undefined && !msg.topic.includes(\"reset\")) {\n return;\n}\nlet type = \"sensor\";\n// Filter UoM from payload\nif (msg.topic == \"wifi_signal\")\n msg.payload = msg.payload.match(/^-?\\d+/)[0];\n\n// Inject config\nif (msg.topic.match(/temperature/)) {\n msg.device_class = \"temperature\";\n}\nif (msg.topic == \"hms\") {\n msg.topic = \"HMS\";\n}\nif (msg.topic == \"wifi_signal\") {\n msg.device_class = \"signal_strength\"\n msg.unit_of_measurement = \"dBm\";\n}\n\nif (msg.topic.match(/(.*)fan(.*)/) && msg.topic !== \"fan_gear\") {\n msg.unit_of_measurement = \"%\";\n type = \"fan\";\n if(msg.topic == \"heatbreak_fan\") {\n type = \"sensor\";\n }\n msg.icon = \"mdi:fan\"\n if (msg.topic == \"aux_part_fan\") {\n delete msg.unit_of_measurement;\n type = \"sensor\";\n }\n}\nif (msg.topic.match(/serial/)) {\n msg.icon = \"mdi:barcode\";\n}\nif (msg.topic == \"status\" || msg.topic == \"print_state\") {\n payload.icon = \"mdi:printer-3d\";\n}\nif(msg.topic == \"sdcard\") {\n msg.icon = \"mdi:sd\"\n}\nif (msg.topic == \"print_progress\") {\n msg.unit_of_measurement = \"%\";\n}\nif(msg.topic == \"print_remaining_time\") {\n msg.unit_of_measurement = \"min\";\n msg.device_class = \"duration\";\n}\nelse if (msg.topic.match(/time/)) {\n msg.icon = \"mdi:clock\";\n if(msg.topic.includes(\"_start_time\")){\n msg.icon = \"mdi:clock-start\";\n } \n else if (msg.topic.includes(\"_end_time\")) {\n msg.icon = \"mdi:clock-end\";\n }\n}\nif(msg.topic == \"speed\") {\n msg.icon = \"mdi:speedometer\"\n}\n\nif (msg.topic == \"SW_version\") {\n device.sw_version = msg.payload;\n}\nif (msg.topic == \"HW_version\") {\n device.hw_version = msg.payload;\n}\nif(msg.topic == \"pause_print\") {\n msg.icon = \"mdi:pause\";\n}\nif (msg.topic == \"resume_print\") {\n msg.icon = \"mdi:play\";\n}\nif (msg.topic == \"stop_print\") {\n msg.icon = \"mdi:cancel\";\n}\nif(msg.topic == \"stage\") {\n msg.icon = \"mdi:state-machine\";\n}\nif(msg.topic == \"HMS\") {\n msg.icon = \"mdi:message-alert-outline\"\n}\nif (msg.topic == \"nozzle_diameter\") {\n msg.icon = \"mdi:printer-3d-nozzle\"\n}\n\nfunction getFriendlyName(str) {\n var i, word = str.split('_');\n for (i = 0; i < word.length; i++) {\n word[i] = word[i].charAt(0).toUpperCase() + word[i].slice(1);\n }\n return word.join(' ');\n}\n\nif(msg.topic == \"chamber_light\") {\n type = \"light\";\n} \nif (msg.topic == \"print_preview\") {\n type = \"camera\";\n payload.image_encoding = \"b64\";\n}\n\nif (msg.topic == \"reset_filter\" || msg.topic == \"pause_print\" || msg.topic == \"resume_print\" || msg.topic == \"stop_print\" || msg.topic == \"force_update\"\n || msg.topic == \"logo_light_on\" || msg.topic == \"clear_external_spool\"\n || msg.topic == \"unload_filament\"\n || msg.topic == \"logo_light_off\" || msg.topic.includes(\"nozzle_light\")) {\n type = \"button\";\n}\nif(msg.topic == \"speed\") {\n type = \"select\";\n}\nif(msg.topic.startsWith(\"set_\") && msg.topic.endsWith(\"_temp\")) {\n type = \"number\";\n payload.min = 0;\n if(msg.topic.includes(\"bed\")) {\n payload.max = 110;\n }\n if(msg.topic.includes(\"nozzle\")) {\n payload.max = 300;\n }\n payload.mode = \"box\";\n}\n\nlet base_topic = \"homeassistant/\"+ type + \"/\" + msg.machine_name + \"/\" + msg.topic;\ndata.topic = base_topic + \"/config\";\npayload.name = getFriendlyName(msg.topic);\nif (msg.topic == \"big_fan2\") {\n payload.name = \"Chamber Fan\";\n}\nelse if (msg.topic == \"big_fan1\") {\n payload.name = \"Auxilliary Fan\";\n}\nelse if (msg.topic == \"cooling_fan\") {\n payload.name = \"Part Cooling Fan\";\n}\nelse if (msg.topic == \"HMS\") {\n payload.name = \"HMS Errors\";\n}\nelse if (msg.topic == \"vt_tray\") {\n payload.name = \"External Spool\";\n}\nelse if (msg.topic == \"aux_part_fan\") {\n payload.name = \"Aux Fan Installed\";\n} else if (msg.topic == \"last_calibrated_pa\") {\n //payload.expire_after = 3600 * 24;\n payload.name = \"Last Calibrated PA\";\n}\n\ndevice.identifiers = [];\ndevice.identifiers[0] = msg.machine_name;\nif (msg.topic == \"serial_number\") {\n device.identifiers[1] = msg.payload;\n}\ndevice.manufacturer = \"Bambu Labs\";\ndevice.model = msg.model;\ndevice.name = msg.machine_name;\n\nif( msg.icon != undefined) {\n payload.icon = msg.icon\n}\n\npayload.device = device;\npayload.unique_id = msg.machine_name + \"_\" + msg.topic;\npayload.object_id = payload.unique_id;\n\nif (msg.device_class != undefined)\n payload.device_class = msg.device_class;\n\nif (msg.unit_of_measurement != undefined)\n payload.unit_of_measurement = msg.unit_of_measurement;\n\nif (payload.device_class == \"temperature\") {\n payload.unit_of_measurement = \"°C\";\n payload.temperature_unit = \"°C\";\n}\n\nif (msg.topic == \"machine_serial\") {\n return;\n}\npayload.state_topic = base_topic + \"/state\";\npayload.json_attributes_topic = base_topic + \"/attr\";\nif(type == \"fan\") {\n payload.command_topic = \"homeassistant/\" + type + \"/\" + msg.machine_name + \"/\" + msg.topic + \"/set\";\n delete payload.json_attributes_topic;\n payload.percentage_command_topic = \"homeassistant/\" + type + \"/\" + msg.machine_name + \"/\" + msg.topic + \"/percent/set\";\n payload.percentage_state_topic = \"homeassistant/\" + type + \"/\" + msg.machine_name + \"/\" + msg.topic + \"/percent/state\";\n payload.speed_range_max = 10;\n payload.speed_range_min = 1;\n}\nif (type == \"light\") {\n payload.command_topic = base_topic + \"/set\";\n delete payload.json_attributes_topic;\n}\nif(type == \"number\") {\n delete payload.json_attributes_topic;\n payload.command_topic = base_topic + \"/set\";\n payload.state_topic = base_topic + \"/set\";\n}\nif (type == \"button\" && msg.topic.includes(\"reset_filter\")) {\n delete payload.state_topic;\n delete payload.json_attributes_topic;\n payload.command_topic = \"homeassistant/\" + \"button\" + \"/\" + msg.machine_name + \"/\" + msg.topic;\n //payload.availability_topic = \"homeassistant/\" + \"sensor\" + \"/\" + msg.machine_name + \"/\" + \"status\" + \"/state\";\n}\nif (type == \"button\" && (msg.topic.includes(\"logo_light\") || msg.topic.includes(\"nozzle_light\"))) {\n delete payload.state_topic;\n delete payload.json_attributes_topic;\n payload.command_topic = \"homeassistant/\" + \"button\" + \"/\" + msg.machine_name + \"/\" + msg.topic;\n payload.availability_topic = \"homeassistant/\" + \"sensor\" + \"/\" + msg.machine_name + \"/\" + \"status\" + \"/state\";\n}\nif (type == \"button\" && (msg.topic.includes(\"clear_external_spool\")\n || msg.topic == \"unload_filament\")) {\n payload.command_topic = \"homeassistant/\" + \"button\" + \"/\" + msg.machine_name + \"/\" + msg.topic;\n\n payload.availability_topic = \"homeassistant/\" + \"sensor\" + \"/\" + msg.machine_name + \"/\" + \"status\" + \"/state\";\n}\nelse if (type == \"button\") {\n delete payload.state_topic;\n delete payload.json_attributes_topic;\n payload.command_topic = \"homeassistant/\" + \"button\" + \"/\" + msg.machine_name + \"/\" + msg.topic;\n if(msg.topic.includes(\"_print\")) {\n let available = \"\";\n if(msg.topic.includes(\"pause\")) {\n available = \"RUNNING\";\n }\n else if(msg.topic.includes(\"resume\")) {\n available = \"PAUSE\";\n }\n else if(msg.topic.includes(\"stop\")) {\n available = \"IS_RUNNING\"\n }\n else {\n return;\n }\n payload.availability = [];\n let a1 = {};\n a1.topic = \"homeassistant/\" + \"sensor\" + \"/\" + msg.machine_name + \"/\" + \"print_status\" + \"/state\";\n a1.payload_available = available;\n a1.payload_not_available = \"N/A\";\n delete payload.availability_topic;\n if(msg.topic.includes(\"stop\")) {\n a1.value_template = '{{ \"' + available + '\" if value == \"RUNNING\" or value == \"PAUSE\" else \"N/A\" }}'\n } else {\n a1.value_template = '{{ \"'+available+'\" if value == \"'+available+'\" else \"N/A\" }}'\n }\n payload.availability.push(a1);\n }\n else if (msg.topic == \"force_update\") {\n payload.availability_topic = \"homeassistant/\" + \"sensor\" + \"/\" + msg.machine_name + \"/\" + \"status\" + \"/state\";\n }\n}\nif (type == \"camera\") {\n payload.topic = base_topic + \"/image\";\n payload.json_attributes_topic = base_topic + \"/attr\";\n payload.availability_topic = \"homeassistant/\" + \"sensor\" + \"/\" + msg.machine_name + \"/\" + \"status\" + \"/state\";\n delete payload.state_topic;\n}\nif(msg.topic == \"serial_number\" || msg.topic.includes(\"version\")) {\n payload.availability_topic = \"homeassistant/\" + \"sensor\" + \"/\" + msg.machine_name + \"/\" + \"status\" + \"/state\";\n}\n\nif (msg.topic == \"speed\") {\n payload.command_topic = \"homeassistant/\" + \"select\" + \"/\" + msg.machine_name + \"/\" + msg.topic + \"/set\";\n payload.state_topic = \"homeassistant/\" + \"select\" + \"/\" + msg.machine_name + \"/\" + msg.topic + \"/state\";\n payload.json_attributes_topic = \"homeassistant/\" + \"select\" + \"/\" + msg.machine_name + \"/\" + msg.topic + \"/attr\";\n payload.availability_topic = \"homeassistant/\" + \"sensor\" + \"/\" + msg.machine_name + \"/\" + \"status\" + \"/state\";\n payload.options = [\"Silent\", \"Standard\", \"Sport\", \"Ludicrous\"]; \n}\n\nif (msg.topic != \"status\" && msg.topic != \"print_status\"\n && msg.topic != \"vt_tray\"\n && msg.topic != \"resume_print\" && msg.topic != \"pause_print\" && msg.topic != \"stop_print\"\n && msg.topic != \"machine_name\" && msg.topic != \"machine_serial\") {\n payload.availability_topic = \"homeassistant/\" + \"sensor\" + \"/\" + msg.machine_name + \"/\" + \"status\" + \"/state\";\n\n}\n\ndata.payload = payload;\n\ndata.qos = 1;\ndata.retain = true;\nif(data.topic.includes(\"homeassistant\")) {\n node.send(data);\n}\n\npayload.name = getFriendlyName(msg.topic);\npayload.unique_id = msg.machine_name + \"_\" + msg.topic;\npayload.object_id = payload.unique_id;\ndelete payload.command_topic;\ndelete payload.options;\ndelete payload.json_attributes_topic;\ndelete payload.state_topic;\npayload.availability_topic = \"homeassistant/\" + \"sensor\" + \"/\" + msg.machine_name + \"/\" + \"status\" + \"/state\"; \ndata.qos = 1;\ndata.retain = true;\n\nif (msg.topic == \"big_fan2\") {\n payload.name = \"Chamber Fan\";\n}\nelse if (msg.topic == \"big_fan1\") {\n payload.name = \"Auxilliary Fan\";\n}\nelse if (msg.topic == \"cooling_fan\") {\n payload.name = \"Part Cooling Fan\";\n}\n\npayload.state_topic = base_topic + \"/state\";\npayload.json_attributes_topic = base_topic + \"/attr\";\nif (type == \"fan\") {\n delete payload.json_attributes_topic;\n delete payload.percentage_command_topic;\n delete payload.percentage_state_topic;\n payload.state_topic = \"homeassistant/\" + \"sensor\" + \"/\" + msg.machine_name + \"/\" + msg.topic + \"/state\";\n delete payload.speed_range_max;\n delete payload.speed_range_min;\n data.topic = \"homeassistant/\" + \"sensor\" + \"/\" + msg.machine_name + \"/\" + msg.topic + \"/config\";\n data.payload = payload;\n if (data.topic.includes(\"homeassistant\")) {\n node.send(data);\n }\n\n}\n\nif (msg.topic == \"speed\") {\n msg.topic = \"speed_info\";\n type = \"sensor\";\n let base_topic = \"homeassistant/\" + \"sensor\" + \"/\" + msg.machine_name + \"/\" + msg.topic;\n \n payload.state_topic = base_topic + \"/state\";\n payload.json_attributes_topic = base_topic + \"/attr\";\n data.eeeeeeeeeee = \"AAAA\";\n data.topic = base_topic + \"/config\";\n data.payload = payload;\n\n if (data.topic.includes(\"homeassistant\")) {\n node.send(data);\n }\n\n}\n\nif(msg.topic == \"stage\") {\n payload.name = \"Lidar Usage\";\n payload.unique_id = msg.machine_name + \"_\" + \"lidar_usage\";\n payload.object_id = payload.unique_id;\n type = \"device_automation\"\n let base_topic = \"homeassistant/\" + type + \"/\" + msg.machine_name + \"/\" + \"lidar_on\";\n\n payload.topic = \"homeassistant/\" + \"sensor\" + \"/\" + msg.machine_name + \"/\" + msg.topic + \"/state\";\n payload.value_template = '{{ \"on\" if \"lidar\" in value|lower else \"off\" }}';\n payload.payload = \"on\";\n\n payload.type = \"in use\";\n payload.automation_type = \"trigger\";\n\n payload.subtype = \"Lidar\";\n data.topic = base_topic + \"/config\";\n \n data.payload = payload;\n node.send(data);\n\n base_topic = \"homeassistant/\" + type + \"/\" + msg.machine_name + \"/\" + \"lidar_off\";\n payload.payload = \"off\";\n\n payload.automation_type = \"trigger\";\n\n payload.type = \"not in use\";\n data.topic = base_topic + \"/config\";\n\n data.payload = payload;\n if (data.topic.includes(\"homeassistant\")) {\n node.send(data);\n }\n\n}\n",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1760,
"y": 580,
"wires": [
[
"135e57a801b6e9bf"
]
]
},
{
"id": "86e9caa98fa51352",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Printer State",
"func": "// Filter UoM from payload\nif (msg.payload == undefined) {\n return;\n}\nif (msg.topic == \"machine_serial\" || msg.topic == \"print_preview\") {\n return;\n}\nif (msg.topic == \"reset_filter\" || msg.topic == \"resume_print\" || msg.topic == \"pause_print\"\n || msg.topic == \"clear_external_spool\"\n || msg.topic.includes(\"logo_light\") || msg.topic.includes(\"nozzle_light\")) {\n return;\n}\nif(msg.topic.startsWith(\"set_\") && msg.topic.endsWith(\"_temp\")) {\n return;\n}\nelse if (msg.topic == \"last_calibrated_pa\" && msg.payload == \"\") {\n return;\n}\nelse if (msg.topic == \"machine_name\") {\n var oldTopic = msg.topic;\n msg.topic = \"homeassistant/sensor/\" + msg.machine_name + \"/\" + msg.topic + \"/attr\";\n let oldPayload = msg.payload;\n msg.payload = {\"Serial Number\": msg.machine_serial};\n node.send(msg);\n msg.payload = oldPayload;\n msg.topic = oldTopic;\n}\nelse if (msg.topic == \"wifi_signal\")\n msg.payload = msg.payload.match(/^-?\\d+/)[0];\nelse if (msg.topic == \"xcam\") {\n var oldTopic = msg.topic;\n msg.topic = \"homeassistant/sensor/\" + msg.machine_name + \"/\" + msg.topic + \"/attr\";\n node.send(msg);\n msg.topic = oldTopic;\n msg.payload = msg.payload.status;\n}\nelse if (msg.topic == \"upload\") {\n var oldTopic = msg.topic;\n msg.topic = \"homeassistant/sensor/\" + msg.machine_name + \"/\" + msg.topic + \"/attr\";\n node.send(msg);\n msg.topic = oldTopic;\n msg.payload = msg.payload.message;\n}\nelse if (msg.topic == \"upgrade_state\") {\n var oldTopic = msg.topic;\n msg.topic = \"homeassistant/sensor/\" + msg.machine_name + \"/\" + msg.topic + \"/attr\";\n node.send(msg);\n msg.topic = oldTopic;\n let state = \"AVAILABLE\";\n if (msg.payload.new_version_state == 1) {\n msg.payload = state;\n }\n else {\n msg.payload = msg.payload.status;\n }\n}\nelse if (msg.topic == \"stage\") {\n var oldTopic = msg.topic;\n msg.topic = \"homeassistant/sensor/\" + msg.machine_name + \"/\" + msg.topic + \"/attr\";\n\n var current = msg.payload.current;\n var prev = {};\n var count = 0;\n for (var stg of msg.payload.prev) {\n prev[count.toString()] = stg;\n count += 1;\n }\n msg.payload = prev;\n node.send(msg);\n msg.topic = oldTopic;\n msg.payload = current;\n}\nelse if (msg.topic == \"ipcam\") {\n var oldTopic = msg.topic;\n msg.topic = \"homeassistant/sensor/\" + msg.machine_name + \"/\" + msg.topic + \"/attr\";\n node.send(msg);\n msg.topic = oldTopic;\n msg.payload = msg.payload.ipcam_dev;\n}\nelse if (msg.topic == \"vt_tray\") {\n var oldTopic = msg.topic;\n msg.topic = \"homeassistant/sensor/\" + msg.machine_name + \"/\" + msg.topic + \"/attr\";\n node.send(msg);\n msg.topic = oldTopic;\n msg.payload = msg.payload.type;\n}\nelse if (msg.topic == \"subtask\") {\n var oldTopic = msg.topic;\n msg.topic = \"homeassistant/sensor/\" + msg.machine_name + \"/\" + msg.topic + \"/attr\";\n node.send(msg);\n msg.topic = oldTopic;\n msg.payload = msg.payload.name;\n}\nelse if (msg.topic == \"print\") {\n var oldTopic = msg.topic;\n msg.topic = \"homeassistant/sensor/\" + msg.machine_name + \"/\" + msg.topic + \"/attr\";\n node.send(msg);\n msg.topic = oldTopic;\n msg.payload = msg.payload.type;\n}\nelse if (msg.topic == \"bed_temperature\") {\n var oldTopic = msg.topic;\n msg.topic = \"homeassistant/sensor/\" + msg.machine_name + \"/\" + msg.topic + \"/attr\";\n node.send(msg);\n msg.topic = oldTopic;\n msg.payload = msg.payload.temperature;\n}\nelse if (msg.topic == \"nozzle_temperature\") {\n var oldTopic = msg.topic;\n msg.topic = \"homeassistant/sensor/\" + msg.machine_name + \"/\" + msg.topic + \"/attr\";\n node.send(msg);\n msg.topic = oldTopic;\n msg.payload = msg.payload.temperature;\n}\nelse if (msg.topic == \"chamber_temperature\") {\n msg.payload = msg.payload.temperature;\n}\nelse if (msg.topic == \"gcode\") {\n var oldTopic = msg.topic;\n msg.topic = \"homeassistant/sensor/\" + msg.machine_name + \"/\" + msg.topic + \"/attr\";\n node.send(msg);\n msg.topic = oldTopic;\n msg.payload = msg.payload.file;\n}\nelse if (msg.topic == \"hms\") {\n msg.topic = \"HMS\";\n var oldTopic = msg.topic;\n var numOfCodes = msg.payload == undefined ? 0 : msg.payload.length;\n msg.topic = \"homeassistant/sensor/\" + msg.machine_name + \"/\" + msg.topic + \"/attr\";\n var links = {};\n for (var data of msg.payload) {\n links[data.code] = data.url;\n }\n msg.payload = links;\n node.send(msg);\n msg.topic = oldTopic;\n msg.payload = numOfCodes;\n}\nelse if (msg.topic == \"speed\") {\n var oldTopic = msg.topic;\n msg.topic = \"homeassistant/select/\" + msg.machine_name + \"/\" + msg.topic + \"/attr\";\n node.send(msg);\n msg.topic = \"homeassistant/sensor/\" + msg.machine_name + \"/\" + \"speed_info\" + \"/attr\";\n node.send(msg);\n msg.topic = \"speed\";\n msg.payload = msg.payload.profile;\n msg.topic = \"homeassistant/select/\" + msg.machine_name + \"/\" + \"speed\" + \"/state\";\n node.send(msg);\n msg.topic = \"homeassistant/sensor/\" + msg.machine_name + \"/\" + \"speed_info\" + \"/state\";\n node.send(msg);\n return;\n}\nelse if (msg.topic == \"chamber_light\") {\n msg.payload = msg.payload.toUpperCase();\n msg.topic = \"homeassistant/light/\" + msg.machine_name + \"/\" + msg.topic + \"/state\";\n node.send(msg);\n return;\n}\nelse if (msg.topic.match(/(.*)fan(.*)/) && msg.topic !== \"fan_gear\" && msg.topic != \"heatbreak_fan\"\n && msg.topic != \"aux_part_fan\") {\n let orig_topic = msg.topic;\n msg.topic = \"homeassistant/sensor/\" + msg.machine_name + \"/\" + orig_topic + \"/state\";\n node.send(msg);\n msg.topic = \"homeassistant/fan/\" + msg.machine_name + \"/\" + orig_topic + \"/percent/state\";\n msg.payload = parseInt(msg.payload) / 10;\n node.send(msg);\n if(msg.payload == 0 || msg.payload == \"0\") {\n msg.payload = \"OFF\";\n msg.topic = \"homeassistant/fan/\" + msg.machine_name + \"/\" + orig_topic+ \"/state\";\n node.send(msg);\n }\n else {\n msg.payload = \"ON\";\n msg.topic = \"homeassistant/fan/\" + msg.machine_name + \"/\" + orig_topic + \"/state\";\n node.send(msg);\n }\n return;\n}\nmsg.topic = \"homeassistant/sensor/\" + msg.machine_name + \"/\" + msg.topic + \"/state\";\n\n\nnode.send(msg);\n",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1750,
"y": 620,
"wires": [
[
"135e57a801b6e9bf"
]
]
},
{
"id": "41797ced12627146",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"property": "topic",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "lights",
"vt": "str"
},
{
"t": "eq",
"v": "fans",
"vt": "str"
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 3,
"x": 1370,
"y": 560,
"wires": [
[
"b2881b8ed28a467c"
],
[
"b2881b8ed28a467c"
],
[
"682e4da1ee0769d4"
]
]
},
{
"id": "2ce84ba9618b908d",
"type": "split",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"splt": "\\n",
"spltType": "str",
"arraySplt": 1,
"arraySpltType": "len",
"stream": false,
"addname": "topic",
"x": 1250,
"y": 540,
"wires": [
[
"41797ced12627146"
]
]
},
{
"id": "b2881b8ed28a467c",
"type": "split",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"splt": "\\n",
"spltType": "str",
"arraySplt": 1,
"arraySpltType": "len",
"stream": false,
"addname": "topic",
"x": 1510,
"y": 620,
"wires": [
[
"682e4da1ee0769d4"
]
]
},
{
"id": "96b92ea713edd221",
"type": "comment",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "X1C",
"info": "",
"x": 1070,
"y": 300,
"wires": []
},
{
"id": "f7de3b0a2a7c5661",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "printer",
"func": "msg.topic = \"X1C\";//_\" + msg.payload.id;\n\nmsg.machine_name = msg.topic + \"_\" + msg.payload.machine_name;\nmsg.model = \"X1 Carbon\";\nmsg.payload.fans = {};\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1070,
"y": 220,
"wires": [
[
"c912472120552915"
]
]
},
{
"id": "8399cea217e486b9",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Fix Start Date",
"func": "if(msg.payload.gcode_state != undefined && \n msg.payload.gcode_start_time != undefined) {\n\n if (msg.payload.gcode_state == \"IDLE\" ||\n msg.payload.gcode_start_time == \"0\" || msg.payload.gcode_start_time == \"N/A\") {\n msg.payload.gcode_start_time = \"N/A\";\n msg.payload.gcode_end_time = \"N/A\";\n }\n else {\n msg.payload.gcode_start_time = msg.payload.gcode_start_time + \"000\";\n }\n}\nelse if (msg.payload.gcode_start_time != undefined && \n msg.payload.gcode_start_time != \"0\") {\n msg.payload.gcode_start_time = msg.payload.gcode_start_time + \"000\"; \n}\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1380,
"y": 220,
"wires": [
[
"5774338c2d9e049b"
]
]
},
{
"id": "f0bcc0434d35f8db",
"type": "mqtt in",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "HomeAssistant In",
"topic": "homeassistant/light/X1C_{PRINTER_NAME}/chamber_light/set",
"qos": "2",
"datatype": "utf8",
"broker": "489094618c340eef",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 140,
"y": 460,
"wires": [
[
"2a0268a55eadf72f"
]
]
},
{
"id": "1db470110f18fab6",
"type": "mqtt out",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "bambu-mqtt-out {PRINTER_NAME}",
"topic": "device/{PRINTER_SERIAL}/request",
"qos": "1",
"retain": "false",
"respTopic": "",
"contentType": "",
"userProps": "",
"correl": "",
"expiry": "",
"broker": "{GENERATED_PRINTER_MQTT_ID}",
"x": 970,
"y": 1140,
"wires": []
},
{
"id": "2a0268a55eadf72f",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Toggle Chamber Light",
"func": "var on = { \"system\": { \"sequence_id\": \"2003\", \"command\": \"ledctrl\", \"led_node\": \"chamber_light\", \"led_mode\": \"on\", \"led_on_time\": 500, \"led_off_time\": 500, \"loop_times\": 0, \"interval_time\": 0 }, \"user_id\": \"123456789\" }\nvar off = { \"system\": { \"sequence_id\": \"2003\", \"command\": \"ledctrl\", \"led_node\": \"chamber_light\", \"led_mode\": \"off\", \"led_on_time\": 500, \"led_off_time\": 500, \"loop_times\": 0, \"interval_time\": 0 }, \"user_id\": \"123456789\" }\n\nif(msg.payload == \"ON\") {\n node.send({\"payload\": on});\n}\nelse if (msg.payload == \"OFF\") {\n node.send({ \"payload\": off });\n}",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 180,
"y": 500,
"wires": [
[
"e34f034bed456673"
]
]
},
{
"id": "c93c3bb2cc88b9dc",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Set Speed Profile",
"func": "var template = { \n \"print\": {\n \"sequence_id\": \"2004\", \n \"command\": \"print_speed\",\n \"param\": \"2\" \n },\n \"user_id\": \"1234567890\"\n}\n\n// In case you want to send a string message\nif (msg.payload !== undefined) {\n switch (msg.payload) {\n case \"Silent\":\n template.print.param= \"1\";\n break;\n case \"Standard\":\n template.print.param = \"2\";\n break;\n case \"Sport\":\n template.print.param = \"3\";\n break;\n case \"Ludicrous\":\n template.print.param = \"4\";\n break;\n default:\n return;\n }\n}\nif (global.get(\"{PRINTER_NAME}_is_connected\", \"true\")) {\n node.send({ \"payload\": template });\n}\n",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 170,
"y": 580,
"wires": [
[
"e34f034bed456673"
]
]
},
{
"id": "d8d2dad22b354fdf",
"type": "mqtt in",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "HomeAssistant In",
"topic": "homeassistant/select/X1C_{PRINTER_NAME}/speed/set",
"qos": "2",
"datatype": "utf8",
"broker": "489094618c340eef",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 140,
"y": 540,
"wires": [
[
"c93c3bb2cc88b9dc"
]
]
},
{
"id": "e9f7f1de7feb3909",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Set Connection Global {PRINTER_NAME}",
"func": "\nif (msg.payload !== undefined && msg.payload.code !== undefined\n && msg.payload.code == 0) {\n if(global.get(\"{PRINTER_NAME}_is_connected\") == \"false\") {\n node.send({});\n }\n global.set(\"{PRINTER_NAME}_is_connected\", \"true\");\n\n} else {\n global.set(\"{PRINTER_NAME}_is_connected\", \"false\");\n}",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1990,
"y": 1200,
"wires": [
[
"51e0ffef53d5bc20"
]
]
},
{
"id": "dce813c208a9da90",
"type": "inject",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Inject OFFLINE {PRINTER_NAME}",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
},
{
"p": "machine_name",
"v": "X1C_{PRINTER_NAME}",
"vt": "str"
},
{
"p": "machine_serial",
"v": "{PRINTER_SERIAL}",
"vt": "str"
}
],
"repeat": "15",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "printer",
"payload": "{\"print_status\":\"OFFLINE\",\"status\":\"offline\",\"machine_name\":\"{PRINTER_NAME}\",\"machine_serial\":\"{PRINTER_SERIAL}\",\"reset_filter\":\"\",\"force_update\":\"\",\"ams_count\":0}",
"payloadType": "json",
"x": 210,
"y": 380,
"wires": [
[
"ab7f1b7beb3a2f80"
]
]
},
{
"id": "ab7f1b7beb3a2f80",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"property": "{PRINTER_NAME}_is_connected",
"propertyType": "global",
"rules": [
{
"t": "eq",
"v": "false",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 1,
"x": 210,
"y": 420,
"wires": [
[
"f844bda465c93ddd"
]
]
},
{
"id": "080745c0307e0218",
"type": "change",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Change Attribute Names",
"rules": [
{
"t": "move",
"p": "payload.tray_type",
"pt": "msg",
"to": "payload.type",
"tot": "msg"
},
{
"t": "move",
"p": "payload.tray_color",
"pt": "msg",
"to": "payload.color",
"tot": "msg"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 690,
"y": 860,
"wires": [
[
"735003dd7602e7dc"
]
]
},
{
"id": "8a61805ce8145c12",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"property": "payload.print.command",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "push_status",
"vt": "str"
},
{
"t": "eq",
"v": "gcode_line",
"vt": "str"
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 3,
"x": 750,
"y": 320,
"wires": [
[
"1389ca15cce63bbb"
],
[],
[]
]
},
{
"id": "eec5b5dc9281ea93",
"type": "comment",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Filters",
"info": "These switch statements act as filters.\n\nFirst one acts to split mc_print and print\nand others\n\nSecond is to only accept \"push_status\" commands.\nOtherwise \"gcode_line\" and others are sent.\n\n(Gcode line is, for example,\nchanging speed profile)",
"x": 870,
"y": 320,
"wires": []
},
{
"id": "6a13ae7af77d563d",
"type": "comment",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "(?) Timezone",
"info": "Timezone configuration may be needed\nif the readable-dates format\nis not in your current timezone.\n\nThis should be using the NR System timezone\nbut in case it doesn't, add it.\n\nI.E. After $moment(var)\nput .tz(your/timezone)\nthen keep the .format after\n\n$moment(msg.payload.gcode_start_time).format(\"MMMM D, yyyy [at] h:mm A\")\n->\n$moment(msg.payload.gcode_start_time).tz(YOUR_TIMEZOME).format(\"MMMM D, yyyy [at] h:mm A\")",
"x": 1070,
"y": 340,
"wires": []
},
{
"id": "5c4b13a29c630b8c",
"type": "comment",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "MC_Print",
"info": "",
"x": 600,
"y": 200,
"wires": []
},
{
"id": "b5232b827fbef671",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Get AMS Humidity",
"func": "if (msg.payload.mc_print != undefined && msg.payload.mc_print.command == \"push_info\") {\n if (msg.payload.mc_print.param != undefined && msg.payload.mc_print.param.startsWith(\"[AMS][TASK]\")) {\n if(msg.payload.mc_print.param.includes(\"humidity\")) {\n let param = msg.payload.mc_print.param;\n let amsId = param.match(/ams(\\d+) /)[1];\n let humidity = param.match(/humidity:(\\d+)%/)[1];\n\n msg.topic = \"AMS\";\n\n msg.machine_name = msg.topic + \"_\" + amsId + \"_\" + msg.payload.mc_print.machine_name;\n \n msg.payload = {\n \"humidity\": humidity\n }\n node.send(msg);\n }\n }\n}\n\n",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 930,
"y": 440,
"wires": [
[
"4a696bec52ae5acb"
]
]
},
{
"id": "4a696bec52ae5acb",
"type": "split",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"splt": "\\n",
"spltType": "str",
"arraySplt": 1,
"arraySpltType": "len",
"stream": false,
"addname": "topic",
"x": 890,
"y": 480,
"wires": [
[
"c40efe7b1b254622"
]
]
},
{
"id": "962c0c56346e023a",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"property": "payload.mc_print.param",
"propertyType": "msg",
"rules": [
{
"t": "cont",
"v": "humidity",
"vt": "str"
},
{
"t": "cont",
"v": "[BMC] M900",
"vt": "str"
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 3,
"x": 610,
"y": 240,
"wires": [
[
"b5232b827fbef671"
],
[
"8548eff7812ded96"
],
[]
]
},
{
"id": "db012956ddb6c2af",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 1020,
"y": 600,
"wires": [
[
"f7de3b0a2a7c5661"
]
]
},
{
"id": "ad4f3f980f172128",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 1520,
"y": 380,
"wires": [
[
"cdbbe3908ea0d90e"
]
]
},
{
"id": "ecf4cb43eed20ca0",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 580,
"y": 740,
"wires": [
[
"2a60f3818c07cead",
"7ec4f5ae5c5f4a57"
]
]
},
{
"id": "b3ee63836831ea89",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 1360,
"y": 860,
"wires": [
[
"e98417ec17a23249"
]
]
},
{
"id": "b5fb8a1a65b4686b",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 1000,
"y": 880,
"wires": [
[
"1f0305e93eed961a"
]
]
},
{
"id": "682e4da1ee0769d4",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 1620,
"y": 580,
"wires": [
[
"472a15482a731de8",
"86e9caa98fa51352"
]
]
},
{
"id": "e98417ec17a23249",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 1860,
"y": 860,
"wires": [
[
"67aa1b3a6a0ac3d7"
]
]
},
{
"id": "135e57a801b6e9bf",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 1860,
"y": 620,
"wires": [
[
"e98417ec17a23249"
]
]
},
{
"id": "7f4faea318d59bed",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 1420,
"y": 1040,
"wires": [
[
"b2881b8ed28a467c"
]
]
},
{
"id": "9a2aaf740774a256",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 540,
"y": 1040,
"wires": [
[
"7f4faea318d59bed"
]
]
},
{
"id": "f844bda465c93ddd",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 500,
"y": 420,
"wires": [
[
"9a2aaf740774a256"
]
]
},
{
"id": "e34f034bed456673",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 340,
"y": 580,
"wires": [
[
"2fe75ce36321f506"
]
]
},
{
"id": "dba47578907a6d23",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 440,
"y": 300,
"wires": [
[
"a365818fb4a53f52"
]
]
},
{
"id": "735003dd7602e7dc",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 1080,
"y": 860,
"wires": [
[
"ff09ef39735c8dd8",
"1f0305e93eed961a"
]
]
},
{
"id": "c40efe7b1b254622",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 1000,
"y": 560,
"wires": [
[
"b34fe28bd6f1cf0b"
]
]
},
{
"id": "b34fe28bd6f1cf0b",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 1060,
"y": 560,
"wires": [
[
"735003dd7602e7dc"
]
]
},
{
"id": "883a607fd81a0e23",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 500,
"y": 260,
"wires": [
[
"962c0c56346e023a"
]
]
},
{
"id": "67aa1b3a6a0ac3d7",
"type": "rbe",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"func": "rbe",
"gap": "",
"start": "",
"inout": "out",
"septopics": true,
"property": "payload",
"topi": "topic",
"x": 1950,
"y": 860,
"wires": [
[
"c868c39bb6549391"
]
]
},
{
"id": "c868c39bb6549391",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"property": "topic",
"propertyType": "msg",
"rules": [
{
"t": "neq",
"v": "",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 1,
"x": 2070,
"y": 900,
"wires": [
[
"17945f4d7962a94a"
]
]
},
{
"id": "af54a0a5940dd334",
"type": "change",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Convert Timestamps",
"rules": [
{
"t": "set",
"p": "payload.gcode_start_time",
"pt": "msg",
"to": "$moment(msg.payload.gcode_start_time).format(\"MMMM D, yyyy [at] h:mm A\")",
"tot": "jsonata"
},
{
"t": "set",
"p": "payload.gcode_end_time",
"pt": "msg",
"to": "$moment(msg.payload.gcode_end_time).format(\"MMMM D, yyyy [at] h:mm A\")",
"tot": "jsonata"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 1280,
"y": 340,
"wires": [
[
"ad4f3f980f172128"
]
]
},
{
"id": "ca1821a15d5fe203",
"type": "comment",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Configure",
"info": "Configure the reset timer here for the filter\n\nThis will reset the filter on an interval\nsuch that when HA is restarted or\nwhen first importing, it should reset values\nproperly.",
"x": 120,
"y": 900,
"wires": []
},
{
"id": "6db1d3c86598f8a4",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 1860,
"y": 1000,
"wires": [
[
"67aa1b3a6a0ac3d7"
]
]
},
{
"id": "0c9c48807302abbe",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 500,
"y": 1000,
"wires": [
[
"6526126078390137"
]
]
},
{
"id": "7cbd22af688976aa",
"type": "inject",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Reset Timer Interval",
"props": [
{
"p": "reset",
"v": "true",
"vt": "bool"
},
{
"p": "machine_name",
"v": "X1C_{PRINTER_NAME}",
"vt": "str"
},
{
"p": "model",
"v": "X1 Carbon",
"vt": "str"
}
],
"repeat": "300",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"x": 160,
"y": 940,
"wires": [
[
"0c9c48807302abbe",
"804bf6ba99e0a70d"
]
]
},
{
"id": "12d493bc4868cb6b",
"type": "mqtt in",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "HomeAssistant In",
"topic": "homeassistant/button/X1C_{PRINTER_NAME}/reset_filter",
"qos": "2",
"datatype": "utf8",
"broker": "489094618c340eef",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 120,
"y": 980,
"wires": [
[
"0c9c48807302abbe"
]
]
},
{
"id": "6526126078390137",
"type": "change",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Reset",
"rules": [
{
"t": "set",
"p": "reset",
"pt": "msg",
"to": "true",
"tot": "bool"
},
{
"t": "set",
"p": "topic",
"pt": "msg",
"to": "",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 1730,
"y": 1000,
"wires": [
[
"6db1d3c86598f8a4"
]
]
},
{
"id": "f6805ea36226a930",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Get_Version Command",
"func": "var template = {\n \"info\": {\n \"sequence_id\": \"20004\",\n \"command\": \"get_version\"\n },\n \"user_id\": \"1234567890\"\n}\nif (global.get(\"{PRINTER_NAME}_is_connected\", \"true\")) {\n node.send({ \"payload\": template });\n}\n",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 210,
"y": 660,
"wires": [
[
"2fe75ce36321f506"
]
]
},
{
"id": "c1bc72e5401a7523",
"type": "inject",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Fetch Versions",
"props": [],
"repeat": "60",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"x": 140,
"y": 620,
"wires": [
[
"f6805ea36226a930"
]
]
},
{
"id": "97e117e5e3b6b2ac",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"property": "payload.info.command",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "get_version",
"vt": "str"
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 2,
"x": 790,
"y": 180,
"wires": [
[
"574efe9bef59bfe8"
],
[]
]
},
{
"id": "dbd5442f44b5d5eb",
"type": "comment",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Info",
"info": "",
"x": 790,
"y": 140,
"wires": []
},
{
"id": "574efe9bef59bfe8",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Parse Versions",
"func": "let data = {\n \"printer\": {}\n};\n\nif(msg.payload.info.module !== undefined) {\n for(var m of msg.payload.info.module) {\n\n if (m.name.includes(\"ams/\")) {\n let n = \"AMS\"+ m.name.replace(\"ams/\", \"\");\n data[n] = {};\n data[n].SW_version = m.sw_ver;\n data[n].serial_number = m.sn;\n data[n].HW_version = m.hw_ver;\n continue;\n }\n else {\n switch(m.name) {\n case \"ota\":\n data.printer.SW_version = m.sw_ver;\n break;\n case \"rv1126\":\n data.printer.serial_number = m.sn;\n data.printer.HW_version = m.hw_ver;\n break;\n case \"esp32\":\n data.printer.serial_number = m.sn;\n data.printer.HW_version = m.hw_ver;\n break;\n }\n continue;\n }\n }\n msg.payload = data;\n node.send(msg);\n}\n",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 980,
"y": 160,
"wires": [
[
"dff0a7bcab99db34"
]
]
},
{
"id": "dff0a7bcab99db34",
"type": "split",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"splt": "\\n",
"spltType": "str",
"arraySplt": 1,
"arraySpltType": "len",
"stream": false,
"addname": "topic",
"x": 1150,
"y": 120,
"wires": [
[
"2dcd252aec842a4b"
]
]
},
{
"id": "17dc50ac469fdac7",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "ams",
"func": "let name = msg.topic.replace(\"AMS\", \"AMS_\");\nmsg.machine_name = name + \"_\" + msg.printer_name;\nmsg.topic = \"AMS\";\nmsg.model = \"AMS\";\nmsg.printer_serial = msg.machine_serial;\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1290,
"y": 120,
"wires": [
[
"0539d7216c7abb63"
]
]
},
{
"id": "51c3cfdad1576d27",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "printer",
"func": "msg.topic = \"X1C\";//_\" + msg.payload.id;\n\nmsg.machine_name = msg.topic + \"_\" + msg.printer_name;\nmsg.model = \"X1 Carbon\";\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1290,
"y": 160,
"wires": [
[
"dae563cbc58f46bd"
]
]
},
{
"id": "2dcd252aec842a4b",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"property": "topic",
"propertyType": "msg",
"rules": [
{
"t": "cont",
"v": "AMS",
"vt": "str"
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 2,
"x": 1150,
"y": 160,
"wires": [
[
"17dc50ac469fdac7"
],
[
"51c3cfdad1576d27"
]
]
},
{
"id": "0539d7216c7abb63",
"type": "split",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"splt": "\\n",
"spltType": "str",
"arraySplt": 1,
"arraySpltType": "len",
"stream": false,
"addname": "topic",
"x": 1410,
"y": 120,
"wires": [
[
"73ce7dbb92cee565"
]
]
},
{
"id": "dae563cbc58f46bd",
"type": "split",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"splt": "\\n",
"spltType": "str",
"arraySplt": 1,
"arraySpltType": "len",
"stream": false,
"addname": "topic",
"x": 1410,
"y": 160,
"wires": [
[
"1105b8629aa017ee"
]
]
},
{
"id": "1105b8629aa017ee",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 1600,
"y": 160,
"wires": [
[
"682e4da1ee0769d4"
]
]
},
{
"id": "73ce7dbb92cee565",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 1500,
"y": 200,
"wires": [
[
"4293665f8ddd9f37"
]
]
},
{
"id": "4293665f8ddd9f37",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 920,
"y": 180,
"wires": [
[
"c40efe7b1b254622"
]
]
},
{
"id": "2fe75ce36321f506",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 480,
"y": 820,
"wires": [
[
"bbb04109ed20f916"
]
]
},
{
"id": "a1c7a965b0d664fe",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Convert HMS Codes",
"func": "function DecimalHexTwosComplement(decimal) {\n var size = 8;\n var hexadecimal;\n if (decimal >= 0) {\n hexadecimal = decimal.toString(16);\n\n while ((hexadecimal.length % size) != 0) {\n hexadecimal = \"\" + 0 + hexadecimal;\n }\n\n return hexadecimal;\n } else {\n hexadecimal = Math.abs(decimal).toString(16);\n while ((hexadecimal.length % size) != 0) {\n hexadecimal = \"\" + 0 + hexadecimal;\n }\n\n var output = '';\n for (var i = 0; i < hexadecimal.length; i++) {\n output += (0x0F - parseInt(hexadecimal[i], 16)).toString(16);\n }\n\n output = (0x01 + parseInt(output, 16)).toString(16);\n return output;\n }\n}\n\nlet template = []\nif(msg.payload.print.hms != undefined){\n for (var hms_code of msg.payload.print.hms) {\n var attr = DecimalHexTwosComplement(hms_code.attr);\n var code = DecimalHexTwosComplement(hms_code.code);\n let full_code = (attr + code).replace(/(.{4})/g, \"$1_\");\n full_code = full_code.substring(0, full_code.length - 1);\n let url = \"https://wiki.bambulab.com/en/x1/troubleshooting/hmscode/\"+full_code;\n template.push({\"code\": \"HMS_\"+full_code, \"url\": url, \"description\":\"\"});\n }\n msg.payload.print.hms = template;\n}\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 820,
"y": 520,
"wires": [
[
"7c6b4583707029ea"
]
]
},
{
"id": "3907f3b052894ad1",
"type": "mqtt in",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "HomeAssistant In",
"topic": "homeassistant/button/X1C_{PRINTER_NAME}/pause_print",
"qos": "2",
"datatype": "utf8",
"broker": "489094618c340eef",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 140,
"y": 700,
"wires": [
[
"d20b02ea37dbdddf"
]
]
},
{
"id": "a4d29254d471acd7",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Pause/Resume/Stop",
"func": "var pause = { \"print\": { \"sequence_id\": \"2008\", \"command\": \"pause\" }, \"user_id\": \"123456789\" }\nvar resume = { \"print\": { \"sequence_id\": \"2009\", \"command\": \"resume\"}, \"user_id\": \"123456789\" }\nvar stop = { \"print\": { \"sequence_id\": \"2010\", \"command\": \"stop\" }, \"user_id\": \"123456789\" }\n\nif(msg.payload == \"PAUSE\") {\n node.send({\"payload\": pause});\n}\nelse if (msg.payload == \"RESUME\") {\n node.send({ \"payload\": resume });\n}\nelse if(msg.payload == \"STOP\") {\n node.send({\"payload\": stop})\n}",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 200,
"y": 820,
"wires": [
[
"2fe75ce36321f506"
]
]
},
{
"id": "1288bcdd3d2bc704",
"type": "mqtt in",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "HomeAssistant In",
"topic": "homeassistant/button/X1C_{PRINTER_NAME}/resume_print",
"qos": "2",
"datatype": "utf8",
"broker": "489094618c340eef",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 140,
"y": 740,
"wires": [
[
"8959434b99b38bdd"
]
]
},
{
"id": "d20b02ea37dbdddf",
"type": "change",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "pause",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "PAUSE",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 290,
"y": 700,
"wires": [
[
"7ba7e522b0b73697"
]
]
},
{
"id": "8959434b99b38bdd",
"type": "change",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "resume",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "RESUME",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 300,
"y": 740,
"wires": [
[
"7ba7e522b0b73697"
]
]
},
{
"id": "7ba7e522b0b73697",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 400,
"y": 760,
"wires": [
[
"a4d29254d471acd7"
]
]
},
{
"id": "ebe6d4b6979d7c94",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Cull Fail Msg",
"func": "if (msg.payload.print != undefined && msg.payload.print.result != undefined\n&& msg.payload.print.result == \"FAIL\" ) {\n//\n}\nelse if(msg.payload != undefined && Object.keys(msg.payload).length > 0){\n node.send(msg);\n}",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 350,
"y": 300,
"wires": [
[
"dba47578907a6d23"
]
]
},
{
"id": "804bf6ba99e0a70d",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Force Update",
"func": "var template = {\n \"pushing\": {\n \"sequence_id\": \"1\",\n \"command\": \"pushall\"\n },\n \"user_id\": \"1234567890\"\n}\n\nif (global.get(\"{PRINTER_NAME}_is_connected\", \"true\")) {\n node.send({ \"payload\": template });\n}\n",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 380,
"y": 1060,
"wires": [
[
"891080cdc3c0148e",
"8040953d45a1e453"
]
]
},
{
"id": "1186527cf1f7ec0e",
"type": "mqtt in",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "HomeAssistant In",
"topic": "homeassistant/button/X1C_{PRINTER_NAME}/force_update",
"qos": "2",
"datatype": "utf8",
"broker": "489094618c340eef",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 120,
"y": 1020,
"wires": [
[
"804bf6ba99e0a70d"
]
]
},
{
"id": "891080cdc3c0148e",
"type": "delay",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"pauseType": "delay",
"timeout": "500",
"timeoutUnits": "milliseconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"x": 390,
"y": 1020,
"wires": [
[
"0c9c48807302abbe"
]
]
},
{
"id": "2f43a94e4c1c67b7",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Primary Organize",
"func": "if(msg.payload.print != undefined) {\n msg.payload.printer = msg.payload.print;\n delete msg.payload.print;\n}\nif (msg.payload.printer != undefined) {\n if(msg.payload.printer.ams != undefined) {\n msg.payload.ams = msg.payload.printer.ams;\n delete msg.payload.printer.ams;\n\n if(msg.payload.ams.ams != undefined) {\n msg.payload.printer.ams_count = msg.payload.ams.ams.length;\n }\n else {\n msg.payload.printer.ams_count = 0;\n }\n }\n if (msg.payload.printer.lights_report != undefined) {\n delete msg.payload.printer.lights_report;\n }\n if (msg.payload.printer.spd_lvl != undefined) {\n delete msg.payload.printer.spd_lvl;\n }\n if (msg.payload.printer.spd_mag != undefined) {\n delete msg.payload.printer.spd_mag;\n }\n if (msg.payload.printer.xcam_status != undefined) {\n if (msg.payload.printer.xcam == undefined) {\n msg.payload.printer.xcam = {};\n }\n msg.payload.printer.xcam.status = msg.payload.printer.xcam_status;\n delete msg.payload.printer.xcam_status;\n }\n}\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 650,
"y": 600,
"wires": [
[
"8d2a544a9c61d783"
]
]
},
{
"id": "ceef34fb1803fabb",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Organize AMS",
"func": "if(msg.payload.ams != undefined) {\n msg.ams = msg.payload.ams;\n delete msg.payload;\n msg.payload = msg.ams;\n delete msg.ams;\n // only send if there's actually ams data\n node.send(msg);\n}",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 640,
"y": 640,
"wires": [
[
"07ff86f3cd404e2d"
]
]
},
{
"id": "3e88e7f16efe9866",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Change Humidity Name",
"func": "if (msg.payload.humidity != undefined) {\n msg.payload.humidity_level = msg.payload.humidity;\n delete msg.payload.humidity;\n}\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 790,
"y": 680,
"wires": [
[
"9693988d17d6b075"
]
]
},
{
"id": "9693988d17d6b075",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 580,
"y": 720,
"wires": [
[
"a0317478d3f43ecf",
"ecf4cb43eed20ca0"
]
]
},
{
"id": "7ec4f5ae5c5f4a57",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 900,
"y": 740,
"wires": [
[
"ff09ef39735c8dd8"
]
]
},
{
"id": "c912472120552915",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Start Epoch",
"func": "if (msg.payload.gcode_start_time != undefined) {\n msg.payload.gcode_start_epoch = msg.payload.gcode_start_time;\n}\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1210,
"y": 220,
"wires": [
[
"8399cea217e486b9"
]
]
},
{
"id": "9271157140e4588a",
"type": "change",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Convert Timestamps",
"rules": [
{
"t": "set",
"p": "payload.gcode_start_time",
"pt": "msg",
"to": "$moment(msg.payload.gcode_start_time).format(\"MMMM D, yyyy [at] h:mm A\")",
"tot": "jsonata"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 1280,
"y": 380,
"wires": [
[
"ad4f3f980f172128"
]
]
},
{
"id": "11d9daa56bb64de3",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"property": "payload.gcode_start_time",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "N/A",
"vt": "str"
},
{
"t": "null"
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 3,
"x": 1510,
"y": 260,
"wires": [
[
"3514fee9e8cb92a1"
],
[
"3514fee9e8cb92a1"
],
[
"9271157140e4588a"
]
]
},
{
"id": "cdbbe3908ea0d90e",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Remove Useless",
"func": "if (msg.payload.command != undefined) {\n delete msg.payload.command;\n}\nif (msg.payload.force_upgrade != undefined) {\n delete msg.payload.force_upgrade;\n}\nif (msg.payload.home_flag != undefined) {\n delete msg.payload.home_flag;\n}\nif (msg.payload.hw_switch_state != undefined) {\n delete msg.payload.hw_switch_state;\n}\nif (msg.payload.lifecycle != undefined) {\n delete msg.payload.lifecycle;\n}\nif (msg.payload.online != undefined) {\n delete msg.payload.online;\n}\nif (msg.payload.ams_rfid_status != undefined) {\n delete msg.payload.ams_rfid_status;\n}\nif (msg.payload.ams_status != undefined) {\n delete msg.payload.ams_status;\n}\nif (msg.payload.manufacturer != undefined) {\n delete msg.payload.manufacturer;\n}\nif(msg.payload.sequence_id != undefined) {\n delete msg.payload.sequence_id;\n}\nif(msg.payload.filam_bak != undefined) {\n delete msg.payload.filam_bak;\n}\n\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1270,
"y": 420,
"wires": [
[
"214dc07ca387eb0a"
]
]
},
{
"id": "214dc07ca387eb0a",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Reorder Print Info",
"func": "if (msg.payload.gcode_file != undefined) {\n if(msg.payload.gcode == undefined) {\n msg.payload.gcode = {};\n }\n msg.payload.gcode.file = msg.payload.gcode_file;\n delete msg.payload.gcode_file;\n}\n\nif (msg.payload.gcode_file_prepare_percent != undefined) {\n if (msg.payload.gcode == undefined) {\n msg.payload.gcode = {};\n }\n msg.payload.gcode.gcode_file_prepare_percent = msg.payload.gcode_file_prepare_percent;\n delete msg.payload.gcode_file_prepare_percent;\n}\n\nif (msg.payload.gcode_start_time != undefined) {\n\n msg.payload.print_start_time = msg.payload.gcode_start_time;\n delete msg.payload.gcode_start_time;\n}\n\nif (msg.payload.gcode_end_time != undefined) {\n\n msg.payload.print_end_time = msg.payload.gcode_end_time;\n delete msg.payload.gcode_end_time;\n}\n\nif (msg.payload.gcode_state != undefined) {\n\n msg.payload.print_status = msg.payload.gcode_state;\n delete msg.payload.gcode_state;\n}\n\nif (msg.payload.mc_percent != undefined) {\n\n msg.payload.print_progress = msg.payload.mc_percent;\n delete msg.payload.mc_percent;\n}\n\nif (msg.payload.mc_print_error_code != undefined) {\n if(msg.payload.print == undefined) {\n msg.payload.print = {};\n }\n msg.payload.print.error_code = msg.payload.mc_print_error_code;\n delete msg.payload.mc_print_error_code;\n}\n\nif (msg.payload.mc_print_stage != undefined) {\n if (msg.payload.print == undefined) {\n msg.payload.print = {};\n }\n msg.payload.print.stage = msg.payload.mc_print_stage;\n delete msg.payload.mc_print_stage;\n}\n\nif (msg.payload.mc_print_sub_stage != undefined) {\n if (msg.payload.print == undefined) {\n msg.payload.print = {};\n }\n msg.payload.print.substage = msg.payload.mc_print_sub_stage;\n delete msg.payload.mc_print_sub_stage;\n}\n\nif (msg.payload.print_error != undefined) {\n if (msg.payload.print == undefined) {\n msg.payload.print = {};\n }\n msg.payload.print.error = msg.payload.print_error;\n delete msg.payload.print_error;\n}\n\nif (msg.payload.print_gcode_action != undefined) {\n if (msg.payload.print == undefined) {\n msg.payload.print = {};\n }\n msg.payload.print.gcode_action = msg.payload.print_gcode_action;\n delete msg.payload.print_gcode_action;\n}\nif (msg.payload.print_real_action != undefined) {\n if (msg.payload.print == undefined) {\n msg.payload.print = {};\n }\n msg.payload.print.real_action = msg.payload.print_real_action;\n delete msg.payload.print_real_action;\n}\nif (msg.payload.print_type != undefined) {\n if (msg.payload.print == undefined) {\n msg.payload.print = {};\n }\n msg.payload.print.type = msg.payload.print_type;\n delete msg.payload.print_type;\n}\n\nif (msg.payload.profile_id != undefined) {\n if (msg.payload.print == undefined) {\n msg.payload.print = {};\n }\n msg.payload.print.profile_id = msg.payload.profile_id;\n delete msg.payload.profile_id;\n}\n\nif (msg.payload.project_id != undefined) {\n if (msg.payload.print == undefined) {\n msg.payload.print = {};\n }\n msg.payload.print.project_id = msg.payload.project_id;\n delete msg.payload.project_id;\n}\n\n\nif (msg.payload.project_id != undefined) {\n if (msg.payload.print == undefined) {\n msg.payload.print = {};\n }\n msg.payload.print.project_id = msg.payload.project_id;\n delete msg.payload.project_id;\n}\n\nif (msg.payload.subtask_name != undefined) {\n if(msg.payload.print == undefined) {\n msg.payload.print = {};\n }\n msg.payload.print.task = msg.payload.subtask_name;\n} \n\nif (msg.payload.mc_remaining_time != undefined) {\n\n msg.payload.print_remaining_time = msg.payload.mc_remaining_time;\n delete msg.payload.mc_remaining_time;\n}\n\nif (msg.payload.gcode_start_epoch != undefined) {\n msg.payload.print_start_epoch = msg.payload.gcode_start_epoch;\n delete msg.payload.gcode_start_epoch;\n}\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1270,
"y": 460,
"wires": [
[
"e4c85d8612f4d7d8"
]
]
},
{
"id": "e4c85d8612f4d7d8",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Reorder Other",
"func": "if (msg.payload.stg_cur != undefined) {\n if(msg.payload.stage == undefined) {\n msg.payload.stage = {};\n }\n msg.payload.stage.current = msg.payload.stg_cur;\n delete msg.payload.stg_cur;\n}\nif (msg.payload.stg != undefined) {\n if (msg.payload.stage == undefined) {\n msg.payload.stage = {};\n }\n msg.payload.stage.prev = msg.payload.stg;\n delete msg.payload.stg;\n}\n\nif (msg.payload.subtask_id != undefined) {\n if (msg.payload.subtask == undefined) {\n msg.payload.subtask = {};\n }\n msg.payload.subtask.id = msg.payload.subtask_id;\n delete msg.payload.subtask_id;\n}\n\nif (msg.payload.subtask_name != undefined) {\n if (msg.payload.subtask == undefined) {\n msg.payload.subtask = {};\n }\n msg.payload.subtask.name = msg.payload.subtask_name;\n delete msg.payload.subtask_name;\n}\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1460,
"y": 460,
"wires": [
[
"147574759061cf4e"
]
]
},
{
"id": "147574759061cf4e",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Reorder Temps + Bed",
"func": "\nif (msg.payload.bed_target_temper != undefined) {\n if (msg.payload.bed_temperature == undefined) {\n msg.payload.bed_temperature = {};\n }\n msg.payload.bed_temperature.target_temperature = msg.payload.bed_target_temper;\n delete msg.payload.bed_target_temper;\n}\nif (msg.payload.bed_temper != undefined) {\n if (msg.payload.bed_temperature == undefined) {\n msg.payload.bed_temperature = {};\n }\n msg.payload.bed_temperature.temperature = msg.payload.bed_temper;\n delete msg.payload.bed_temper;\n}\nif (msg.payload.nozzle_temper != undefined) {\n if (msg.payload.nozzle_temperature == undefined) {\n msg.payload.nozzle_temperature = {};\n }\n msg.payload.nozzle_temperature.temperature = msg.payload.nozzle_temper;\n delete msg.payload.nozzle_temper;\n}\nif (msg.payload.nozzle_target_temper != undefined) {\n if (msg.payload.nozzle_temperature == undefined) {\n msg.payload.nozzle_temperature = {};\n }\n msg.payload.nozzle_temperature.target_temperature = msg.payload.nozzle_target_temper;\n delete msg.payload.nozzle_target_temper;\n}\n\n\nif (msg.payload.big_fan1_speed != undefined) {\n if(msg.payload.fans == undefined) {\n msg.payload.fans = {};\n }\n msg.payload.fans.big_fan1 = msg.payload.big_fan1_speed;\n delete msg.payload.big_fan1_speed;\n}\nif (msg.payload.big_fan2_speed != undefined) {\n if (msg.payload.fans == undefined) {\n msg.payload.fans = {};\n }\n msg.payload.fans.big_fan2 = msg.payload.big_fan2_speed;\n delete msg.payload.big_fan2_speed;\n}\nif (msg.payload.heatbreak_fan_speed != undefined) {\n if (msg.payload.fans == undefined) {\n msg.payload.fans = {};\n }\n msg.payload.fans.heatbreak_fan = msg.payload.heatbreak_fan_speed;\n delete msg.payload.heatbreak_fan_speed;\n}\nif (msg.payload.cooling_fan_speed != undefined) {\n if (msg.payload.fans == undefined) {\n msg.payload.fans = {};\n }\n msg.payload.fans.cooling_fan = msg.payload.cooling_fan_speed;\n delete msg.payload.cooling_fan_speed;\n}\n\nif(msg.payload.chamber_temper != undefined) {\n if(msg.payload.chamber_temperature == undefined) {\n msg.payload.chamber_temperature = {};\n }\n msg.payload.chamber_temperature.temperature = msg.payload.chamber_temper;\n delete msg.payload.chamber_temper;\n}\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1280,
"y": 500,
"wires": [
[
"edfd9d58baed5c0e"
]
]
},
{
"id": "ba2e021eef1322ea",
"type": "comment",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "VERSION REV:48",
"info": "Rev 46/47: 2023-05-01\n- Removing MQTT configs to be external nodes passing in, so importing multiple flows and updating are easier\n- Added a reconnect for when printer comes online with new mqtt flow. Shouldn't be necessary but added as a backup\n- When HA connects in MQTT now, it will reset the filter so no more waiting 5m on setup. Hopefully\n\n===\nRev 45: 2023-04-29\n- Added Filament Unload button which runs the built in unload procedure\n\n===\nRev 42: 2023-04-27\n- Added sensor for storing the last Pressure Advance value from LIDAR calibration for 24 hours\n\n===\nRev 40/41: 2023-04-27\n- Whoops forgot to change this for 40\n- Added new button to \"clear\" external spool\n\n===\nRev 39: 2023-04-26\n- Add support for plate_type sensor (only filled out by advanced flow with FTP)\n- Support for newest firmware release of X1C 01.05.01.00 (20230426)\n- VT_Tray already implemented for P1P, but renamed to External Spool now.\n\n===\nRev 36: 2023-04-07\n- Changed logic of the global connected status to be ping-based\nEvery 30s we will ping the printer to check if it's online or not.\nThis is because the MQTT will be online if P1P cloud mode, even if printer is not.\n\n\n===\nRev 35: 2023-04-05\n- Added in workaround for allowing P1P to connect using Cloud mode\nThis requires an additional setup flow to set a global attribute\nAnd requires a local flow boolean for P1P_CLOUD_MODE\n\n====\nRev 34: 2023-03-14\n- Added fan speed controls for Chamber, Part and Aux fans.\n- Heatbreak fan is read only currently.\n\n====\nRev 33: 2023-03-11\n\n- Fixed EndTime continuing to increment after print ended\n- In progress but not yet activated placeholders for camera entities\n\n====\nRev 31: 2023-03-05\n\n- Added default icons to some more sensors\n- Added Number Boxes to set Bed and Nozzle Temps within ranges (0-100 bed, 0-300 nozzle)\n- General update for syncing\n\n====\nRev 30: 2023-02-25\n\nChanged a bit how filament fetching works.\nNow it will be unknown, none or the sensor unavailable depending on \"how\" it can't get the filament type in use.\nThis is such that the advanced flow fetching filament type can work better\n(i.e., when it's unavailable here, then filament fetch will work)\n\nIT IS OKAY if the filament sensor is not working fully, that's expected due to limitations.\n\n====\nRev 29: 2023-02-23\n\nFixed: Issue with a junction not being in the group of the last update\n\nAdded: \n - Button to turn on and off nozzle light.\n\n====\nRev 28: 2023-02-23\n\nAdded:\n - New Filament Sensor. This will attempt to get the *type* of filament in use. Really only works for AMS users. Don't worry if it doesn't show up or is unavailable, it just means it can't make a default one and is not considered an error - I just have no way of handling / finding out.\n - New buttons to turn on or off the Logo Light via GCODE - these are buttons and not a light or switch, as I cannot poll for the light status.\n I also from now on will not be including the flow page in the exports, but JUST the group, this should make importing easier for replacement.\n\n",
"x": 130,
"y": 60,
"wires": []
},
{
"id": "17b0dcf3695419d6",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Send Gcode",
"func": "let template = {\n \"print\": {\n \"sequence_id\": \"2026\",\n \"command\": \"gcode_line\",\n \"param\": \"\\n\"\n },\n \"user_id\": \"1234567890\"\n}\n\nif (msg.gcode != undefined && msg.gcode != \"\") {\n\n template.print.param = msg.gcode;\n if(!msg.gcode.endsWith(\"\\n\")) {\n template.print.param = template.print.param + \"\\n\";\n }\n msg.payload = template;\n if (global.get(\"{PRINTER_NAME}_is_connected\", \"true\")) {\n node.send(msg);\n }\n}",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 570,
"y": 1180,
"wires": [
[
"8040953d45a1e453"
]
]
},
{
"id": "193d411066edd78a",
"type": "mqtt in",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "HomeAssistant In",
"topic": "homeassistant/button/X1C_{PRINTER_NAME}/logo_light_on",
"qos": "2",
"datatype": "auto-detect",
"broker": "489094618c340eef",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 120,
"y": 1220,
"wires": [
[
"15f1d2104c14b32d"
]
]
},
{
"id": "cbf991bc44588b46",
"type": "mqtt in",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "HomeAssistant In",
"topic": "homeassistant/button/X1C_{PRINTER_NAME}/logo_light_off",
"qos": "2",
"datatype": "auto-detect",
"broker": "489094618c340eef",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 120,
"y": 1260,
"wires": [
[
"236eb62e785fa16a"
]
]
},
{
"id": "15f1d2104c14b32d",
"type": "change",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Turn Logo On",
"rules": [
{
"t": "set",
"p": "gcode",
"pt": "msg",
"to": "M960 S5 P1",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 300,
"y": 1220,
"wires": [
[
"3a1ed497179905d8"
]
]
},
{
"id": "236eb62e785fa16a",
"type": "change",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Turn Logo Off",
"rules": [
{
"t": "set",
"p": "gcode",
"pt": "msg",
"to": "M960 S5 P0",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 300,
"y": 1260,
"wires": [
[
"3a1ed497179905d8"
]
]
},
{
"id": "ec6f548a5bc948b2",
"type": "change",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "stop",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "STOP",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 310,
"y": 780,
"wires": [
[
"7ba7e522b0b73697"
]
]
},
{
"id": "3b9a660c508f1cb6",
"type": "mqtt in",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "HomeAssistant In",
"topic": "homeassistant/button/X1C_{PRINTER_NAME}/stop_print",
"qos": "2",
"datatype": "utf8",
"broker": "489094618c340eef",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 140,
"y": 780,
"wires": [
[
"ec6f548a5bc948b2"
]
]
},
{
"id": "3a1ed497179905d8",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 460,
"y": 1180,
"wires": [
[
"17b0dcf3695419d6"
]
]
},
{
"id": "bbb04109ed20f916",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 600,
"y": 940,
"wires": [
[
"e556e5d4352c614c"
]
]
},
{
"id": "e556e5d4352c614c",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 760,
"y": 940,
"wires": [
[
"1db470110f18fab6"
]
]
},
{
"id": "8040953d45a1e453",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 680,
"y": 1140,
"wires": [
[
"1db470110f18fab6"
]
]
},
{
"id": "aab0848e64d380c3",
"type": "mqtt in",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "HomeAssistant In",
"topic": "homeassistant/button/X1C_{PRINTER_NAME}/nozzle_light_on",
"qos": "2",
"datatype": "auto-detect",
"broker": "489094618c340eef",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 120,
"y": 1300,
"wires": [
[
"a57684202aa2160e"
]
]
},
{
"id": "a57684202aa2160e",
"type": "change",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Turn Nozzle Light On",
"rules": [
{
"t": "set",
"p": "gcode",
"pt": "msg",
"to": "M960 S4 P1",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 320,
"y": 1300,
"wires": [
[
"dbc27a9fddc3334e"
]
]
},
{
"id": "c8e2eab0fad37985",
"type": "change",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Turn Nozzle Light Off",
"rules": [
{
"t": "set",
"p": "gcode",
"pt": "msg",
"to": "M960 S4 P0",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 320,
"y": 1340,
"wires": [
[
"dbc27a9fddc3334e"
]
]
},
{
"id": "345a439e1ca993a9",
"type": "mqtt in",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "HomeAssistant In",
"topic": "homeassistant/button/X1C_{PRINTER_NAME}/nozzle_light_off",
"qos": "2",
"datatype": "auto-detect",
"broker": "489094618c340eef",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 120,
"y": 1340,
"wires": [
[
"c8e2eab0fad37985"
]
]
},
{
"id": "dbc27a9fddc3334e",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 500,
"y": 1300,
"wires": [
[
"3a1ed497179905d8"
]
]
},
{
"id": "3514fee9e8cb92a1",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 1600,
"y": 240,
"wires": [
[
"ad4f3f980f172128"
]
]
},
{
"id": "2250e65775ee5fba",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Set Bed Target",
"func": "if (msg.payload == undefined || isNaN(msg.payload || \nmsg.payload < 0 || msg.payload > 110)) {\n return;\n}\n\nmsg.gcode = \"M140 S\"+ msg.payload.toString();\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 860,
"y": 1320,
"wires": [
[
"62ac383912a1df6b"
]
]
},
{
"id": "0db02154b69078d5",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Set NozzleTarget",
"func": "if (msg.payload == undefined || isNaN(msg.payload || \nmsg.payload < 0 || msg.payload > 300)) {\n return;\n}\n\nmsg.gcode = \"M104 S\"+ msg.payload.toString();\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 870,
"y": 1360,
"wires": [
[
"62ac383912a1df6b"
]
]
},
{
"id": "e59529e8f4f2b4d7",
"type": "mqtt in",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "HomeAssistant In",
"topic": "homeassistant/number/X1C_{PRINTER_NAME}/set_bed_temp/set",
"qos": "2",
"datatype": "auto-detect",
"broker": "489094618c340eef",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 680,
"y": 1320,
"wires": [
[
"2250e65775ee5fba"
]
]
},
{
"id": "bcf32534e23d8cb5",
"type": "mqtt in",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "HomeAssistant In",
"topic": "homeassistant/number/X1C_{PRINTER_NAME}/set_nozzle_temp/set",
"qos": "2",
"datatype": "auto-detect",
"broker": "489094618c340eef",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 680,
"y": 1360,
"wires": [
[
"0db02154b69078d5"
]
]
},
{
"id": "62ac383912a1df6b",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 1000,
"y": 1240,
"wires": [
[
"3a1ed497179905d8"
]
]
},
{
"id": "edfd9d58baed5c0e",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Fix End Time",
"func": "if(msg.payload.print_end_time != undefined && msg.payload.print_end_time != \"N/A\") {\n if(msg.payload.print_status != undefined) {\n if(msg.payload.print_status == \"FINISH\" || msg.payload.print_status == \"FAILED\") {\n delete msg.payload.print_end_time;\n }\n }\n}\n\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1470,
"y": 500,
"wires": [
[
"2ce84ba9618b908d"
]
]
},
{
"id": "90ec5d0b9ffa32e4",
"type": "mqtt in",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "HomeAssistant In",
"topic": "homeassistant/fan/X1C_{PRINTER_NAME}/big_fan1/percent/set",
"qos": "2",
"datatype": "auto-detect",
"broker": "489094618c340eef",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 1160,
"y": 1220,
"wires": [
[
"248ebd30cb6cf901"
]
]
},
{
"id": "df64a614382d6055",
"type": "mqtt in",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "HomeAssistant In",
"topic": "homeassistant/fan/X1C_{PRINTER_NAME}/big_fan2/percent/set",
"qos": "2",
"datatype": "auto-detect",
"broker": "489094618c340eef",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 1160,
"y": 1260,
"wires": [
[
"248ebd30cb6cf901"
]
]
},
{
"id": "9f88ad5505fac7cf",
"type": "mqtt in",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "HomeAssistant In",
"topic": "homeassistant/fan/X1C_{PRINTER_NAME}/cooling_fan/percent/set",
"qos": "2",
"datatype": "auto-detect",
"broker": "489094618c340eef",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 1160,
"y": 1300,
"wires": [
[
"248ebd30cb6cf901"
]
]
},
{
"id": "5c7aac3c3657ba24",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Toggle Fans",
"func": "let fan = \"\";\nif(msg.topic.includes(\"big_fan2\")) {\n fan = \"P3\";// chamber\n}\nelse if (msg.topic.includes(\"big_fan1\")) {\n fan = \"P2\";// aux\n}\nelse if (msg.topic.includes(\"cooling_fan\")){\n fan = \"P1\"; // part\n}\nelse {\n return;\n}\n\nlet amt = 0;\nif(msg.payload == \"ON\") {\n amt = 51;//20\n}\nelse if (msg.payload == \"OFF\") {\n amt = 0;\n}\nelse {\n return;\n}\n\nmsg.gcode = \"M106 \"+ fan + \" S\"+amt.toString();\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1630,
"y": 1180,
"wires": [
[
"66a2cbf9f289b7aa"
]
]
},
{
"id": "05f30349cf1717a7",
"type": "mqtt in",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "HomeAssistant In",
"topic": "homeassistant/fan/X1C_{PRINTER_NAME}/big_fan1/set",
"qos": "2",
"datatype": "auto-detect",
"broker": "489094618c340eef",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 1480,
"y": 1220,
"wires": [
[
"f1a328459d02685b"
]
]
},
{
"id": "b2e7df90b8407c7a",
"type": "mqtt in",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "HomeAssistant In",
"topic": "homeassistant/fan/X1C_{PRINTER_NAME}/big_fan2/set",
"qos": "2",
"datatype": "auto-detect",
"broker": "489094618c340eef",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 1480,
"y": 1260,
"wires": [
[
"f1a328459d02685b"
]
]
},
{
"id": "fc410f217da7eda4",
"type": "mqtt in",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "HomeAssistant In",
"topic": "homeassistant/fan/X1C_{PRINTER_NAME}/cooling_fan/set",
"qos": "2",
"datatype": "auto-detect",
"broker": "489094618c340eef",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 1480,
"y": 1300,
"wires": [
[
"f1a328459d02685b"
]
]
},
{
"id": "70d2024d191a082e",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Change Fan Speeds",
"func": "let fan = \"\";\nif(msg.topic.includes(\"big_fan2\")) {\n fan = \"P3\";// chamber\n}\nelse if (msg.topic.includes(\"big_fan1\")) {\n fan = \"P2\";// aux\n}\nelse if (msg.topic.includes(\"cooling_fan\")){\n fan = \"P1\"; // part\n}\nelse {\n return;\n}\n\nlet amt = 0;\nswitch (msg.payload) {\n case 0: \n amt = 0;\n break;\n case 1: \n amt = 30;\n break;\n case 2: \n amt = 51;\n break;\n case 3:\n amt = 80;\n break;\n case 4:\n amt = 102;\n break;\n case 5:\n amt = 127;\n break;\n case 6:\n amt = 153;\n break;\n case 7:\n amt = 179;\n break;\n case 8:\n amt = 204;\n break;\n case 9:\n amt = 230;\n break;\n case 10:\n amt = 255;\n break;\n default:\n amt = 51;\n break;\n}\n\nmsg.gcode = \"M106 \"+ fan + \" S\"+amt.toString();\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1360,
"y": 1180,
"wires": [
[
"66a2cbf9f289b7aa"
]
]
},
{
"id": "66a2cbf9f289b7aa",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 1540,
"y": 1140,
"wires": [
[
"3a1ed497179905d8"
]
]
},
{
"id": "f1a328459d02685b",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 1640,
"y": 1260,
"wires": [
[
"5c7aac3c3657ba24"
]
]
},
{
"id": "248ebd30cb6cf901",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 1300,
"y": 1260,
"wires": [
[
"70d2024d191a082e"
]
]
},
{
"id": "92a884a3331bfa4b",
"type": "inject",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Startup Trigger",
"props": [
{
"p": "start_status",
"v": "1",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": "5",
"topic": "",
"x": 160,
"y": 140,
"wires": [
[
"5cd82175da584146"
]
]
},
{
"id": "5cd82175da584146",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"property": "P1P_CLOUD_MODE",
"propertyType": "flow",
"rules": [
{
"t": "true"
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 2,
"x": 310,
"y": 140,
"wires": [
[
"b04f934b4958c998"
],
[
"4c8011bd5cb181a7"
]
]
},
{
"id": "d944c995cf7771e0",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Disconnect",
"func": "let config = {\n \"action\": \"disconnect\"\n}\nnode.send(config);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 370,
"y": 60,
"wires": [
[
"0a5d92c3648ea7af"
]
]
},
{
"id": "8eb8d0318afc5c0b",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 280,
"y": 100,
"wires": [
[
"d944c995cf7771e0",
"6835f39fb902578a"
]
]
},
{
"id": "6835f39fb902578a",
"type": "delay",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"pauseType": "delay",
"timeout": "2",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"x": 380,
"y": 100,
"wires": [
[
"9362a1b7e3670507",
"dcf228c59349178a"
]
]
},
{
"id": "9362a1b7e3670507",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Connect",
"func": "let config = {\n \"action\": \"connect\",\n \"broker\": {\n \"password\": global.get(\"BAMBU_ACCESS_TOKEN\"),\n \"port\": 8883,\n \"broker\": global.get(\"BAMBU_REGION\"),\n \"username\": global.get(\"BAMBU_MQTT_USER\")\n } \n}\n\nnode.send(config);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 540,
"y": 100,
"wires": [
[
"0a5d92c3648ea7af"
]
]
},
{
"id": "0a5d92c3648ea7af",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 640,
"y": 60,
"wires": [
[
"05e6995783570ac3"
]
]
},
{
"id": "92b557ed537a1451",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Subscribe",
"func": "let config = {\n \"action\": \"subscribe\",\n \"topic\": {\n \"topic\":\"device/{PRINTER_SERIAL}/report\",\n \"qos\": 2\n }\n}\n\nnode.send(config);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 440,
"y": 200,
"wires": [
[
"b1c1923cb89b667b"
]
]
},
{
"id": "dcf228c59349178a",
"type": "delay",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"pauseType": "delay",
"timeout": "3",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"x": 480,
"y": 140,
"wires": [
[
"92b557ed537a1451"
]
]
},
{
"id": "128d03867a7d32ad",
"type": "delay",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"pauseType": "delay",
"timeout": "2",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"x": 600,
"y": 1060,
"wires": [
[
"804bf6ba99e0a70d"
]
]
},
{
"id": "05e6995783570ac3",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 700,
"y": 920,
"wires": [
[
"e556e5d4352c614c",
"8f276707783e36e0"
]
]
},
{
"id": "8f276707783e36e0",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 740,
"y": 1080,
"wires": [
[
"128d03867a7d32ad"
]
]
},
{
"id": "b04f934b4958c998",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"property": "BAMBU_ACCESS_TOKEN",
"propertyType": "global",
"rules": [
{
"t": "nempty"
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 2,
"x": 770,
"y": 60,
"wires": [
[
"0e9d8e65b9383827"
],
[
"a6a549b513fe916b"
]
]
},
{
"id": "a6a549b513fe916b",
"type": "delay",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"pauseType": "delay",
"timeout": "5",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"x": 920,
"y": 60,
"wires": [
[
"b04f934b4958c998"
]
]
},
{
"id": "0e9d8e65b9383827",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 720,
"y": 120,
"wires": [
[
"8eb8d0318afc5c0b"
]
]
},
{
"id": "e509c1902d9bb186",
"type": "inject",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "StartupSet",
"props": [],
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": "0.1",
"topic": "",
"x": 1650,
"y": 80,
"wires": [
[
"71f3cd131ac47b5f"
]
]
},
{
"id": "71f3cd131ac47b5f",
"type": "change",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Set Flow Properties",
"rules": [
{
"t": "set",
"p": "P1P_CLOUD_MODE",
"pt": "flow",
"to": "{P1P_IN_CLOUD_MODE}",
"tot": "bool"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 1830,
"y": 80,
"wires": [
[]
]
},
{
"id": "f9ebb81f5664f91d",
"type": "inject",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Check Server Online",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "30",
"crontab": "",
"once": true,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"x": 1940,
"y": 1120,
"wires": [
[
"4521e494acb429e6"
]
]
},
{
"id": "4521e494acb429e6",
"type": "exec",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"command": "ping -c 1 {PRINTER_IP}",
"addpay": "",
"append": "",
"useSpawn": "false",
"timer": "10",
"winHide": false,
"oldrc": false,
"name": "Ping Local Printer",
"x": 1930,
"y": 1160,
"wires": [
[],
[],
[
"e9f7f1de7feb3909"
]
]
},
{
"id": "51e0ffef53d5bc20",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 2120,
"y": 1020,
"wires": [
[
"30917db9b244627a"
]
]
},
{
"id": "b4eef9bbefd37b47",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Clear Virtual Tray",
"func": "let payload = {\n \"print\": {\n \"command\": \"ams_filament_setting\",\n \"sequence_id\": \"2030\",\n \"ams_id\": 255,\n \"tray_id\": 254,\n \"tray_info_idx\": \"\",\n \"setting_id\": \"\",\n \"tray_color\": \"00000000\",\n \"nozzle_temp_min\": 0,\n \"nozzle_temp_max\": 0,\n \"tray_type\": \"\"\n }\n}\nmsg.payload = payload;\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 310,
"y": 1140,
"wires": [
[
"96906ffafad503eb"
]
]
},
{
"id": "956693cec86ba0b4",
"type": "mqtt in",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "HomeAssistant In",
"topic": "homeassistant/button/X1C_{PRINTER_NAME}/clear_external_spool",
"qos": "2",
"datatype": "utf8",
"broker": "489094618c340eef",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 120,
"y": 1140,
"wires": [
[
"b4eef9bbefd37b47"
]
]
},
{
"id": "8548eff7812ded96",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Get PA Calibration",
"func": "if (msg.payload.mc_print != undefined && msg.payload.mc_print.command == \"push_info\") {\n if (msg.payload.mc_print.param != undefined && msg.payload.mc_print.param.startsWith(\"[BMC] M900 K\")) {\n\n let param = msg.payload.mc_print.param;\n let calib_value = param.match(/K(\\d+\\.\\d+)/)[1];\n\n msg.topic = \"last_calibrated_pa\";\n\n msg.machine_name = \"X1C_\" + msg.payload.mc_print.machine_name;\n \n msg.payload = {\n \"last_calibrated_pa\": calib_value\n };\n \n\n node.send(msg); \n }\n}\n\n",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 810,
"y": 240,
"wires": [
[
"58c7d66c6f3c35c4"
]
]
},
{
"id": "58c7d66c6f3c35c4",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 1160,
"y": 620,
"wires": [
[
"b2881b8ed28a467c"
]
]
},
{
"id": "1e92fa493eba35e5",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Unload Filament",
"func": "let payload = {\n \"print\": {\n \"sequence_id\": \"2027\", \n \"command\": \"gcode_file\",\n \"param\": \"/usr/etc/print/filament_unload.gcode\" \n },\n \"user_id\": \"1234567890\"\n };\nmsg.payload = payload;\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 300,
"y": 1180,
"wires": [
[
"96906ffafad503eb"
]
]
},
{
"id": "07466678a4986a7a",
"type": "mqtt in",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "HomeAssistant In",
"topic": "homeassistant/button/X1C_{PRINTER_NAME}/unload_filament",
"qos": "2",
"datatype": "utf8",
"broker": "489094618c340eef",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 120,
"y": 1180,
"wires": [
[
"1e92fa493eba35e5"
]
]
},
{
"id": "96906ffafad503eb",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 440,
"y": 1140,
"wires": [
[
"8040953d45a1e453"
]
]
},
{
"id": "4c8011bd5cb181a7",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Connect",
"func": "let config = {\n \"action\": \"connect\",\n \"broker\": {\n \"password\": \"{ACCESS_CODE}\",\n \"port\": 8883,\n \"broker\": \"{PRINTER_IP}\",\n \"username\":\"bblp\"\n } \n}\n\nnode.send(config);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 120,
"y": 200,
"wires": [
[
"b1c1923cb89b667b",
"c5cc9910c88c94d9"
]
]
},
{
"id": "c5cc9910c88c94d9",
"type": "delay",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"pauseType": "delay",
"timeout": "2",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"x": 280,
"y": 200,
"wires": [
[
"92b557ed537a1451"
]
]
},
{
"id": "9ea2ae26de45d301",
"type": "inject",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Startup Trigger",
"props": [],
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": "1",
"topic": "",
"x": 2000,
"y": 720,
"wires": [
[
"b8012fa88ed7a0a8"
]
]
},
{
"id": "b8012fa88ed7a0a8",
"type": "function",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "Connect",
"func": "let config = {\n \"action\": \"connect\",\n \"broker\": {\n \"password\": \"{HA_MQTT_BROKER_PASS}\",\n \"port\": {HA_MQTT_BROKER_PORT},\n \"broker\": \"{HA_MQTT_BROKER_HOST}\",\n \"username\":\"{HA_MQTT_BROKER_USER}\"\n } \n}\n\nnode.send(config);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 2020,
"y": 760,
"wires": [
[
"17945f4d7962a94a",
"d7d2f90f2ea888c7"
]
]
},
{
"id": "d7d2f90f2ea888c7",
"type": "delay",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"pauseType": "delay",
"timeout": "3",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"x": 1560,
"y": 800,
"wires": [
[
"6526126078390137"
]
]
},
{
"id": "30917db9b244627a",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"x": 880,
"y": 1080,
"wires": [
[
"8f276707783e36e0",
"ee27856bdf0642fc"
]
]
},
{
"id": "ee27856bdf0642fc",
"type": "delay",
"z": "fbda6ab16491b918",
"g": "296274a0d2a6c675",
"name": "",
"pauseType": "delay",
"timeout": "5",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"x": 920,
"y": 940,
"wires": [
[
"5cd82175da584146"
]
]
},
{
"id": "{GENERATED_PRINTER_MQTT_ID}",
"type": "mqtt-broker",
"name": "Bambu X1C MQTT {PRINTER_NAME}",
"broker": "{PRINTER_IP}",
"port": "8883",
"tls": "",
"clientid": "",
"autoConnect": false,
"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": "489094618c340eef",
"type": "mqtt-broker",
"name": "homeassistant",
"broker": "{HA_MQTT_BROKER_HOST}",
"port": "{HA_MQTT_BROKER_PORT}",
"clientid": "",
"autoConnect": false,
"usetls": false,
"protocolVersion": "4",
"keepalive": "60",
"cleansession": true,
"birthTopic": "",
"birthQos": "0",
"birthPayload": "",
"birthMsg": {},
"closeTopic": "",
"closeQos": "0",
"closePayload": "",
"closeMsg": {},
"willTopic": "",
"willQos": "0",
"willPayload": "",
"willMsg": {},
"userProps": "",
"sessionExpiry": ""
}
]
[
{
"id": "35189d41d7e64098",
"type": "trigger-state",
"z": "fbda6ab16491b918",
"name": "When Print Starts",
"server": "ed9339d3bdf92870",
"version": 2,
"exposeToHomeAssistant": false,
"haConfig": [
{
"property": "name",
"value": ""
},
{
"property": "icon",
"value": ""
}
],
"entityid": "sensor.{HA_PRINTER_ENTITY_NAME}_print_status",
"entityidfiltertype": "exact",
"debugenabled": false,
"constraints": [
{
"targetType": "this_entity",
"targetValue": "",
"propertyType": "previous_state",
"propertyValue": "old_state.state",
"comparatorType": "is_not",
"comparatorValueDatatype": "str",
"comparatorValue": "RUNNING"
},
{
"targetType": "this_entity",
"targetValue": "",
"propertyType": "current_state",
"propertyValue": "new_state.state",
"comparatorType": "is",
"comparatorValueDatatype": "str",
"comparatorValue": "RUNNING"
},
{
"targetType": "this_entity",
"targetValue": "",
"propertyType": "previous_state",
"propertyValue": "old_state.state",
"comparatorType": "is_not",
"comparatorValueDatatype": "str",
"comparatorValue": "PAUSE"
},
{
"targetType": "this_entity",
"targetValue": "",
"propertyType": "previous_state",
"propertyValue": "old_state.state",
"comparatorType": "is_not",
"comparatorValueDatatype": "str",
"comparatorValue": "Unknown"
}
],
"inputs": 0,
"outputs": 2,
"customoutputs": [],
"outputinitially": false,
"state_type": "str",
"enableInput": false,
"x": 80,
"y": 1580,
"wires": [
[
"bab486630826f18f"
],
[]
]
},
{
"id": "b37e1ea07031ddb3",
"type": "trigger-state",
"z": "fbda6ab16491b918",
"name": "When Print Ends or Pause",
"server": "ed9339d3bdf92870",
"version": 2,
"exposeToHomeAssistant": false,
"haConfig": [
{
"property": "name",
"value": ""
},
{
"property": "icon",
"value": ""
}
],
"entityid": "sensor.{HA_PRINTER_ENTITY_NAME}_print_status",
"entityidfiltertype": "exact",
"debugenabled": false,
"constraints": [
{
"targetType": "this_entity",
"targetValue": "",
"propertyType": "previous_state",
"propertyValue": "old_state.state",
"comparatorType": "is_not",
"comparatorValueDatatype": "str",
"comparatorValue": "OFFLINE"
},
{
"targetType": "this_entity",
"targetValue": "",
"propertyType": "current_state",
"propertyValue": "new_state.state",
"comparatorType": "is_not",
"comparatorValueDatatype": "str",
"comparatorValue": "OFFLINE"
},
{
"targetType": "this_entity",
"targetValue": "",
"propertyType": "current_state",
"propertyValue": "new_state.state",
"comparatorType": "is_not",
"comparatorValueDatatype": "str",
"comparatorValue": "RUNNING"
},
{
"targetType": "this_entity",
"targetValue": "",
"propertyType": "current_state",
"propertyValue": "new_state.state",
"comparatorType": "is_not",
"comparatorValueDatatype": "str",
"comparatorValue": "IDLE"
},
{
"targetType": "this_entity",
"targetValue": "",
"propertyType": "previous_state",
"propertyValue": "old_state.state",
"comparatorType": "is_not",
"comparatorValueDatatype": "str",
"comparatorValue": ""
},
{
"targetType": "this_entity",
"targetValue": "",
"propertyType": "previous_state",
"propertyValue": "old_state.state",
"comparatorType": "is_not",
"comparatorValueDatatype": "str",
"comparatorValue": "FINISH"
},
{
"targetType": "this_entity",
"targetValue": "",
"propertyType": "previous_state",
"propertyValue": "old_state.state",
"comparatorType": "is_not",
"comparatorValueDatatype": "str",
"comparatorValue": "FAILED"
},
{
"targetType": "this_entity",
"targetValue": "",
"propertyType": "current_state",
"propertyValue": "new_state.state",
"comparatorType": "is_not",
"comparatorValueDatatype": "str",
"comparatorValue": "PREPARE"
}
],
"inputs": 0,
"outputs": 2,
"customoutputs": [],
"outputinitially": false,
"state_type": "str",
"enableInput": false,
"x": 110,
"y": 2100,
"wires": [
[
"a59ef513683810a9"
],
[]
]
},
{
"id": "0a2561d5abf6ca94",
"type": "trigger-state",
"z": "fbda6ab16491b918",
"name": "When Print Resume",
"server": "ed9339d3bdf92870",
"version": 2,
"exposeToHomeAssistant": false,
"haConfig": [
{
"property": "name",
"value": ""
},
{
"property": "icon",
"value": ""
}
],
"entityid": "sensor.{HA_PRINTER_ENTITY_NAME}_print_status",
"entityidfiltertype": "exact",
"debugenabled": false,
"constraints": [
{
"targetType": "this_entity",
"targetValue": "",
"propertyType": "current_state",
"propertyValue": "new_state.state",
"comparatorType": "is",
"comparatorValueDatatype": "str",
"comparatorValue": "RUNNING"
},
{
"targetType": "this_entity",
"targetValue": "",
"propertyType": "previous_state",
"propertyValue": "old_state.state",
"comparatorType": "is",
"comparatorValueDatatype": "str",
"comparatorValue": "PAUSE"
}
],
"inputs": 0,
"outputs": 2,
"customoutputs": [],
"outputinitially": false,
"state_type": "str",
"enableInput": false,
"x": 110,
"y": 2200,
"wires": [
[
"fd7de145f90381e2"
],
[]
]
},
{
"id": "52483d291b252ef5",
"type": "inject",
"z": "fbda6ab16491b918",
"name": "FORCE FETCH",
"props": [
{
"p": "filename",
"v": "",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"x": 100,
"y": 1500,
"wires": [
[
"eb7b7d95a12bca81"
]
]
},
{
"id": "0d11f934236fa7fd",
"type": "comment",
"z": "fbda6ab16491b918",
"name": "Adv Flow: REV 46",
"info": "Rev 39: 2023-04-26\n- Added extracting of plate_type for each print in ftp+postgres flow\n- Set plate_type sensor on x1c printer based on print details\n\n====\nRev 38: 2023-04-20\n- Increased delay when P1P Cloud in fetch\n\n====\nRev 36: 2023-04-07\n- Modified FTP flow to handle P1P in cloud Mode \nIf p1p cloud is toggled on, instead of FTPS, it will wait for the project file message to printer from mqtt server.\nIt will then do a GET download of the url from bambu's amazon webserver instead.\n- Modified Postgres Table schema, will be automatic upgrade.\n- Added a failsafe for start epoch as p1p cloud mode won't have it, this sets it ONLY for the print for DB purposes\n\n====\nRev 33: 2023-03-11\n- Changed FTP Image fetch logic. No longer do you need to rely on caching of a digital file or exposing nodered to the internet. Now, an image will be sent through MQTT (dashboard has associated update)\n\n====\nRev 31: 2023-03-05\n- General update for syncing\n\n====\nRev 30: 2023-02-25\n- Changed image and weight fetching to be fetch for the currently printed plate instead of default plate 1\n- Added \"Filament Type Setter\" to set filament type of printer based on 3mf file via FTPS, instead of relying on AMS in normal flow\n\n",
"x": 110,
"y": 1420,
"wires": []
},
{
"id": "b3dce1cde1787caf",
"type": "comment",
"z": "fbda6ab16491b918",
"name": "Adv Flow: README",
"info": "- If you do not want to have the database stuff, delete the \"Postgres DB\" group.\nThe FTPS fetch and filament type setter will still work without it\n\n- If you have a print start and it didn't fetch the image right or the weight or type,\ngo back here to the nodered flow and click the button on the \"FORCE FETCH\" inject node.",
"x": 110,
"y": 1460,
"wires": []
},
{
"id": "a6e413f2d9026aef",
"type": "inject",
"z": "fbda6ab16491b918",
"name": "FORCE FETCH + DB INIT",
"props": [
{
"p": "filename",
"v": "",
"vt": "str"
}
],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"x": 130,
"y": 1660,
"wires": [
[
"bab486630826f18f"
]
]
},
{
"id": "bab486630826f18f",
"type": "junction",
"z": "fbda6ab16491b918",
"x": 220,
"y": 1580,
"wires": [
[
"eb7b7d95a12bca81",
"9f785ff8ae78f4c8"
]
]
},
{
"id": "a8e16f2f7cd7ca58",
"type": "group",
"z": "fbda6ab16491b918",
"name": "HTTP/FTPS Print Fetch",
"style": {
"stroke": "#ffC000",
"label": true,
"color": "#ffcf3f"
},
"nodes": [
"78542490c91bf887",
"30dad989631cfaa5",
"c67bbd325b89adbf",
"f688049b33fb6a61",
"d7c2cab04b8a0f78",
"33500f62b336ae89",
"51b15b96b7068b55",
"016e9b0f33308095",
"629c07afdacaed2c",
"522957aac1e24443",
"eb7b7d95a12bca81",
"0b423508e8a3515b",
"755f49719d3dd4eb",
"4e223d03cf30c7bd",
"5beec15f7d35c6ec",
"890ab48c5cb98981",
"349fd8f789e58660",
"984eea7487453707",
"1d903d5f9c8a8aa2",
"c24b378aa0b3c889",
"9386d0cbbffcf90b",
"099ae32fd0a1483d",
"6fa4d1a57d7c4e23",
"b45595cb76197d84",
"9f0d8c0185519c96",
"28bb787e0806b511",
"9d7d34a6f1e19c23",
"f9cb0af2a6c85c49",
"c0bfe664d33c9ff8",
"b8bc2487c25657b6",
"dbb49f936e18c921",
"5cc053aff21113dc",
"5b752e13e2378572",
"1d472ed6d3d7a576",
"81f2db0cf1fa2c74",
"2fca17d4bcd36129",
"3f93ad8aa7db7110",
"6aba4661dfa4c7e4",
"7ab3301e83fc0590",
"cac1b7adf2c6d624",
"0795430eee910585",
"c898859abbdf69b0",
"5599c7b710ac608a",
"a3f958f3add4c012",
"4c3f9b3f821499d9",
"08bc28f30a164480",
"26af41f2b243fd25",
"d656805d7bcdc699",
"f25d82ddb0337696",
"c4136d77d81c879f",
"d4849513cf0a8fba",
"83b03ee855471ede",
"eb2bd4860f82f073",
"4df45cdd7a364fff",
"4e66dc111a31e102",
"99b283650ac47d8d",
"98315ed3585697c4"
],
"x": 214,
"y": 1419,
"w": 1392,
"h": 482
},
{
"id": "78542490c91bf887",
"type": "http in",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "GetPreviewImage ",
"url": "/get/media/{PRINTER_NAME}/preview.png",
"method": "get",
"upload": false,
"swaggerDoc": "",
"x": 770,
"y": 1460,
"wires": [
[
"c67bbd325b89adbf"
]
]
},
{
"id": "30dad989631cfaa5",
"type": "http response",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "",
"statusCode": "",
"headers": {
"Cache-control": "no-cache"
},
"x": 1290,
"y": 1460,
"wires": []
},
{
"id": "c67bbd325b89adbf",
"type": "file in",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "Check for existing image",
"filename": "/data/fetched/{PRINTER_NAME}/preview.png",
"filenameType": "str",
"format": "",
"chunk": false,
"sendError": false,
"encoding": "none",
"allProps": false,
"x": 990,
"y": 1460,
"wires": [
[
"522957aac1e24443"
]
]
},
{
"id": "f688049b33fb6a61",
"type": "file in",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "Read 3mf",
"filename": "localFilename",
"filenameType": "msg",
"format": "",
"chunk": false,
"sendError": false,
"encoding": "none",
"allProps": false,
"x": 900,
"y": 1580,
"wires": [
[
"d7c2cab04b8a0f78"
]
]
},
{
"id": "d7c2cab04b8a0f78",
"type": "zip",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "",
"mode": "decompress",
"filename": "",
"compressionlevel": 6,
"outasstring": false,
"x": 1050,
"y": 1540,
"wires": [
[
"28bb787e0806b511"
]
]
},
{
"id": "33500f62b336ae89",
"type": "function",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "Extract Preview Image Buffer",
"func": "var image = null;\nif (msg.payload !== undefined && msg.payload.length > 0) {\n for (var file of msg.payload) {\n if (file.filename == \"Metadata/\"+msg.plate_name+\".png\") {\n image = file.payload;\n break;\n }\n }\n}\n\nif (image !== null) {\n msg.payload = image;\n if(msg.req !== undefined) {\n msg.statusCode = 200;\n }\n node.send(msg);\n}",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 720,
"y": 1620,
"wires": [
[
"016e9b0f33308095"
]
]
},
{
"id": "51b15b96b7068b55",
"type": "file",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "Write Image",
"filename": "/data/fetched/{PRINTER_NAME}/preview.png",
"filenameType": "str",
"appendNewline": false,
"createDir": true,
"overwriteFile": "true",
"encoding": "base64",
"x": 1070,
"y": 1640,
"wires": [
[
"81f2db0cf1fa2c74"
]
],
"info": "This is a backup approach which writes \r\nthe file locally into the NR instance.\r\n\r\n"
},
{
"id": "016e9b0f33308095",
"type": "base64",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "",
"action": "",
"property": "payload",
"x": 920,
"y": 1620,
"wires": [
[
"51b15b96b7068b55"
]
]
},
{
"id": "629c07afdacaed2c",
"type": "delay",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "",
"pauseType": "delay",
"timeout": "1",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"x": 760,
"y": 1580,
"wires": [
[
"f688049b33fb6a61"
]
]
},
{
"id": "522957aac1e24443",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "",
"property": "req",
"propertyType": "msg",
"rules": [
{
"t": "nnull"
}
],
"checkall": "true",
"repair": false,
"outputs": 1,
"x": 1170,
"y": 1460,
"wires": [
[
"30dad989631cfaa5"
]
]
},
{
"id": "eb7b7d95a12bca81",
"type": "delay",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "",
"pauseType": "delay",
"timeout": "1",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"x": 300,
"y": 1460,
"wires": [
[
"6aba4661dfa4c7e4"
]
]
},
{
"id": "0b423508e8a3515b",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "Current Task Filename",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "sensor.{HA_PRINTER_ENTITY_NAME}_subtask",
"state_type": "str",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "filename",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 880,
"y": 1500,
"wires": [
[
"755f49719d3dd4eb"
]
]
},
{
"id": "755f49719d3dd4eb",
"type": "function",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "Check Print File",
"func": "var found = false;\nfor (var obj of msg.files) {\n if (msg.filename == obj || msg.filename + \".3mf\" == obj\n || msg.filename + \".gcode.3mf\" == obj ) {\n msg.filename = \"/\" + obj;\n msg.payload = msg.filename;\n node.send(msg)\n found = true;\n break;\n }\n else if (\"/cache/\" + msg.filename == obj || \"/cache/\" +msg.filename + \".3mf\" == obj\n || \"/cache/\" +msg.filename + \".gcode.3mf\" == obj) {\n msg.filename = obj;\n msg.payload = msg.filename;\n node.send(msg)\n found = true;\n break;\n }\n}\nif (!found) {\n // msg.filename = \"/local_print.gcode.3mf\"\n // msg.payload = msg.filename;\n msg.filename = \"\";\n msg.payload = msg.filename;\n node.send(msg)\n}",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 380,
"y": 1560,
"wires": [
[
"6fa4d1a57d7c4e23"
]
]
},
{
"id": "4e223d03cf30c7bd",
"type": "delay",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "",
"pauseType": "delay",
"timeout": "1",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"x": 700,
"y": 1500,
"wires": [
[
"0b423508e8a3515b"
]
]
},
{
"id": "5beec15f7d35c6ec",
"type": "function",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "Extract Print Data XML",
"func": "var f = null;\nif (msg.payload !== undefined && msg.payload.length > 0) {\n for (var file of msg.payload) {\n if (file.filename == \"Metadata/slice_info.config\") {\n f = file.payload;\n break;\n }\n }\n}\n\nif (f !== null) {\n msg.payload = f;\n if(msg.req !== undefined) {\n msg.statusCode = 200;\n }\n node.send(msg);\n}",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 700,
"y": 1680,
"wires": [
[
"890ab48c5cb98981"
]
]
},
{
"id": "890ab48c5cb98981",
"type": "base64",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "",
"action": "",
"property": "payload",
"x": 920,
"y": 1680,
"wires": [
[
"349fd8f789e58660"
]
]
},
{
"id": "349fd8f789e58660",
"type": "file",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "Write XML",
"filename": "/data/fetched/{PRINTER_NAME}/slicer_info.xml",
"filenameType": "str",
"appendNewline": false,
"createDir": true,
"overwriteFile": "true",
"encoding": "base64",
"x": 1070,
"y": 1680,
"wires": [
[
"f25d82ddb0337696"
]
],
"info": "This is a backup approach which writes \r\nthe file locally into the NR instance.\r\n\r\n"
},
{
"id": "984eea7487453707",
"type": "file in",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "",
"filename": "filename",
"filenameType": "msg",
"format": "utf8",
"chunk": false,
"sendError": false,
"encoding": "none",
"allProps": false,
"x": 660,
"y": 1720,
"wires": [
[
"1d903d5f9c8a8aa2"
]
]
},
{
"id": "1d903d5f9c8a8aa2",
"type": "xml",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "",
"property": "payload",
"attr": "property",
"chr": "",
"x": 830,
"y": 1720,
"wires": [
[
"c24b378aa0b3c889"
]
]
},
{
"id": "c24b378aa0b3c889",
"type": "function",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "Extract Type And Sum Weights",
"func": "var filaments = {};\n\nvar weight = 0.0;\n\nvar current_plate_meta = undefined;\nif (msg.payload !== undefined && msg.payload.config != undefined\n && msg.payload.config.plate != undefined) {\n let plates = msg.payload.config.plate;\n for (var plate of plates) {\n for (var p of plate.metadata) {\n if(p.property.key == \"index\" && \n parseInt(p.property.value) == msg.plate_id) {\n current_plate_meta = plate.metadata;\n break;\n }\n //if (p.property.key == \"weight\") {\n // weight += parseFloat(p.property.value);\n //}\n }\n for (var f of plate.filament) {\n if(f.property.type != undefined && \n !f.property.type.includes(\"Support\")\n && f.property.type != \"PLA-S\"\n && f.property.type != \"PA-S\"\n ) {\n if (filaments[f.property.type] == undefined) {\n filaments[f.property.type] = parseFloat(f.property.used_g);\n }\n else {\n filaments[f.property.type] = filaments[f.property.type] + parseFloat(f.property.used_g);\n }\n }\n }\n }\n}\n\nif(current_plate_meta != undefined) {\n for (var p of current_plate_meta) {\n if (p.property.key == \"weight\") {\n weight += parseFloat(p.property.value);\n }\n }\n}\n\nmsg.payload = {};\nmsg.payload.weight = weight;\nmsg.payload.material = \"\";\nvar fil = Object.keys(filaments);\nvar max = 0;\nfor (var ff of fil) {\n if (filaments[ff] >= max) {\n max = filaments[ff];\n msg.payload.material = ff;\n }\n}\nif (max == 0) {\n msg.payload.material = \"\";\n}\n\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1050,
"y": 1720,
"wires": [
[
"41db1a005f0694bc",
"13ab87bca0a9499a"
]
]
},
{
"id": "9386d0cbbffcf90b",
"type": "python-function-ps",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "List 3MF Files (Py)",
"pythonPathType": "local",
"pythonPath": "python3",
"globalPythonName": "",
"importPathList": [],
"fnCode": "import ftplib\nimport ssl\nimport platform\n\nftplib.ssl_version = ssl.PROTOCOL_TLSv1_2\n\nclass ImplicitFTP_TLS(ftplib.FTP_TLS):\n \"\"\"FTP_TLS subclass that automatically wraps sockets in SSL to support implicit FTPS.\"\"\"\n\n def __init__(self, *args, **kwargs):\n super().__init__(*args, **kwargs)\n self._sock = None\n\n @property\n def sock(self):\n \"\"\"Return the socket.\"\"\"\n return self._sock\n\n @sock.setter\n def sock(self, value):\n \"\"\"When modifying the socket, ensure that it is ssl wrapped.\"\"\"\n if value is not None and not isinstance(value, ssl.SSLSocket):\n value = self.context.wrap_socket(value)\n self._sock = value\n\n def ntransfercmd(self, cmd, rest=None):\n conn, size = ftplib.FTP.ntransfercmd(self, cmd, rest)\n if self._prot_p:\n session = self.sock.session\n if isinstance(self.sock, ssl.SSLSocket):\n session = self.sock.session\n conn = self.context.wrap_socket(conn,\n server_hostname=self.host,\n session=session) # this is the fix\n return conn, size\n \n\nftps = ImplicitFTP_TLS()\n\nftps.connect(host=\"{PRINTER_IP}\", port=990)\n\nftps.login(user=\"bblp\", passwd=\"{ACCESS_CODE}\")\nftps.prot_p()\n\nli = ftps.nlst(\"*.3mf\")\nli2 = ftps.nlst(\"/cache\")\n\nli = li + li2 \nmsg[\"files\"] = li\nftps.close()\nreturn msg\n\n",
"x": 530,
"y": 1500,
"wires": [
[
"4e223d03cf30c7bd"
]
]
},
{
"id": "099ae32fd0a1483d",
"type": "python-function-ps",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "Fetch 3MF File (Py)",
"pythonPathType": "local",
"pythonPath": "python3",
"globalPythonName": "",
"importPathList": [],
"fnCode": "import ftplib\nimport ssl\nimport os\n\nftplib.ssl_version = ssl.PROTOCOL_TLSv1_2\n\nclass ImplicitFTP_TLS(ftplib.FTP_TLS):\n \"\"\"FTP_TLS subclass that automatically wraps sockets in SSL to support implicit FTPS.\"\"\"\n\n def __init__(self, *args, **kwargs):\n super().__init__(*args, **kwargs)\n self._sock = None\n\n @property\n def sock(self):\n \"\"\"Return the socket.\"\"\"\n return self._sock\n\n @sock.setter\n def sock(self, value):\n \"\"\"When modifying the socket, ensure that it is ssl wrapped.\"\"\"\n if value is not None and not isinstance(value, ssl.SSLSocket):\n value = self.context.wrap_socket(value)\n self._sock = value\n\n def ntransfercmd(self, cmd, rest=None):\n conn, size = ftplib.FTP.ntransfercmd(self, cmd, rest)\n if self._prot_p:\n session = self.sock.session\n if isinstance(self.sock, ssl.SSLSocket):\n session = self.sock.session\n conn = self.context.wrap_socket(conn,\n server_hostname=self.host,\n session=session) # this is the fix\n return conn, size\n\nftps = ImplicitFTP_TLS()\n\nftps.connect(host=\"{PRINTER_IP}\", port=990)\n\nftps.login(user=\"bblp\", passwd=\"{ACCESS_CODE}\")\nftps.prot_p()\n\npath = \"/data/fetched/{PRINTER_NAME}\"\nisExist = os.path.exists(path)\nif not isExist:\n os.makedirs(path)\n\nlocalFileName = path + \"/current_print.3mf\"\n\nwith open(localFileName, 'wb') as f:\n ftps.retrbinary('RETR ' + msg[\"payload\"], f.write)\n\nmsg[\"localFilename\"] = localFileName\nftps.close()\nreturn msg\n\n",
"x": 590,
"y": 1580,
"wires": [
[
"629c07afdacaed2c"
]
]
},
{
"id": "6fa4d1a57d7c4e23",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "3MF Found?",
"property": "filename",
"propertyType": "msg",
"rules": [
{
"t": "neq",
"v": "",
"vt": "str"
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 2,
"x": 370,
"y": 1600,
"wires": [
[
"099ae32fd0a1483d"
],
[
"9f0d8c0185519c96"
]
]
},
{
"id": "b45595cb76197d84",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"x": 560,
"y": 1620,
"wires": [
[
"33500f62b336ae89",
"5beec15f7d35c6ec",
"d4849513cf0a8fba"
]
]
},
{
"id": "9f0d8c0185519c96",
"type": "function",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "Default Img Base64",
"func": "var default_image = \"iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAAupnpUWHRSYXcgcHJvZmlsZSB0eXBlIGV4aWYAAHjarZxplh030p7/YxW9BMwBLAfjOd6Bl+/nxa2iOKi/btkWJRbFqpuJBCLeIRBId/73/7ruX//6VwihNpeLtdpr9fyTe+5x8IfmP/+M93vw+f3+/U/4+v2Xv3c//hj5mviaPt9o9etT338ffrmMD4M/lZ8u1NbXN+av3+j58zW23y4UP1+SRqQ/768L9a8Lpfj5Rvi6wPg8lq+92c+PMM/n6/5+0Pb5z+m33H4d9h//b8zeLtwnxXhSSJ7fU4qfAST9l1wa7w/jfZsBp8yfMz829O2vizEhfzdPP/7pjOhqqPlvf+i/Wq3vP7nfVyvHrx9Jv01y/fH1b//ehfLbN9KP+8Sf75zbjzD55e9LeJH34uiX2dd/9+523zPzFCNXprp+PdT3o7w/8XOTW+jWzTG06o3/Cpew96vzqxHVi1DYfvnJrxV6iKzHDTnsMMIN531dYTHEHI+Lxh9iXDG9v2zJYo8rfdaPX+FGSz3t1FjF9ZY9p/hjLOHdtvvl3t0ad96BH42BiwU+8o9/uX/6gXuVCiH49mOuGFeMmmyGoZXT7/wYKxLu16SWN8Hfv37/R+uaWMGiWVaKdCZ2fi4xS/gLCdJb6MQPFr5+cjDY/roAU8StWX2mghVg1UIqoQZvMVoITGRjgQZDjynHyQqEUuJmkJHEqaxNi7o1H7HwfjSWyF87/h4wYyVKqslYm54Gi5VzIX4sN2JolFRyKaUWK630MmqquZZaq1WB4rBk2VmxambNuo2WWm6l1Wattd5Gjz0BmqXXbr313sfgnoMrDz49+IExZpxp5lncrNNmm32ORfisvMqqy1ZbfY0dd9rgx67bdtt9jxMOoXTyKaceO+30My6hdpO7+ZZbr912+x0/Vu1rWf/49Q9WLXytWnwrpR+0H6vG35p9XyIITorWjAWLLgdW3LQEBHTUmvkWco5aOa2Z7+BbKpFBFq3ZDloxVjCfEMsN32vn4mdFtXL/T+vmLP+ybvH/duWclu4frtyf6/Z3q7aFd+ut2CcLNak+kX03KwOqgXnt5pbuAf9GOou/u5ekTad7u/tOZtNbDhneOaXwQ/cKkmfS1/7nZ3/+YHRt+NSZpTj5mbhAWNvR66Pz1tju9KXr/9YdgNy1s0ppA/79vtfnTt39eaNfxxj/uJP3X/f6+U7LfW7k/Z+3+u8fS/dy//CxLKbDdxqxVGrTimodWSxXAqucUxiENosOBaRkJ1or60ZPVI2bcp/8zW0zlt73Br8yVyKqQhhlrlqKbddqyX3Zzh0CK3H0TJzsmvacBPOEPgjuuecbJ6AYbffhrc9aCRKru4CHXMCFHechhcotfa5dzy1H0LAsrjwWA96kXPWX+56VWjjHwuqxztNIwFsHLFXmcZ7/54N1b6aNmbF2jHG3s9OakeybjzdPJ4JtbFJ0X18OwX64566DGJ1zBXejNNs8/D1zwyiv8RytpBkUoKdUC2WEUwOPPpN1MPqMshl/W+jDMmL39TR3cjhtzc2j2F4kQPQkVZgk5WYQZWSyXWKAmb8MEw7YM1WfppkyfJ3Uzyww7bgrGIDG/O1ZRm8s5123V+nAS2KOevfWBxj2XXHODAq9qYl2/CXbJ+nvwBUiLMRsnrTPZ4cFUBybXUKundsOqMGKAIYMYO/VgaDxR5S7n8P85yi3BkXdkO4qPWSWKZ0h+BvTR/BvWmNwIEJqxVu42cU4d2TEukCIM7MwxAkUM9YG+lJ8VGmnph60oCztYhl3O0gvlAlQq9jLTsHHpPzNmML9m1yboAwQ/mc+uv8mIf+bfHT/CWf+W5hx/wln/luYcV+3Y/ZKP/xP+mngpJq3Eb4ezoeNisnKKX6+MllCZf/11fmf/6KckE5aN8wzg92xDpcBBBKRuhupT8xCUVGCsu4IbtR6GDJ04srpbWFb2to+51OHH2ddRp9tWTqBWKxXv5OipfVq5c41wxBI5RazBDTpE9xqaZGSgpd6CaISJyO/cQ2czNinFmIZVXaUas1I5Z3DuL2cufflCSA7MtgcDN0HTwCxFohx5u3POX6CcjwvPDmwfsxctrQ9c7NO3wXBXMbiI5v5BUs6FwI4ufqK6OPF77Mo81lx7nsGKRAT95m2Ur9+GVNVd4iAKE9nQIlfUH03yWMWfUSga7RwucfxJ9c694HWfZ7+INZLR0wQGrB2TvpyBSUezd+C+ckKxOx6zPr3Fn4j0Fgx8mAXpEXYjBRpkBdjBZ97ADhRElaZHuLKI1ZwEreAb6M7yIVVOGT0RLxWheyMBO0CiViUK1g+3uYFpVPfrK5ZQmggbBp2BOAD5Fc7wMggye8ohamASUDJDkZAUoFkDpMPkP48L3KMeUNLQFz7zHYFGsJDVFc2w/cPFukFfJ9M0oTOSAqmE+RkMBltxWe5Vy0gXq17ANTL89DcNI2bAb4bvLxIu0x3KOi+3TBSYG0iFipsZlNPgbq0ryWDEM6JcMlAKg2oFYACXiOPlsYA9kdPlwA8vsKPs0dZtDl2PhclqRBFn03k2gSrIwtD+pB6fACuSlBi2k5cMxJjrJcYNJIMTtipLpHxhNljmLqtpSWARHKNfsBIfMMMkzuFdVtFsNcJT7LGG2ipfU9odhGxEGp89j/CeshVuIHIXBIAAcjWHcV5E216EHKICHQk0WU8TeC+vkxozhMyN3Or7LkPM8BTDJYw8jkgQbkIBkFWpEhp0++KF2EVR5E04QesE0orl9hXZwVQ1H5MI+VMLiGLPj0AQbaSROjmJ1KFUfzrwu8IxVcGVZsSLUnuf4DsIy5/Rq9qZzCAg6oOZbpGdqQJRu4OnHGFBOYcvAOqBpECvy8CO/TRDfbMZ2l+0DtjJ6aTFW4EYcjV7Y659gnukssS9i1hXJxkXHtIHggtJrIRShjnWbyi+mIhmYeDLs9NKIOsWfpwX54AWvgILQwBi3Lh+gQFyGPZT1QPqwN0M773+bCFUP48oECM5tsGa4Fms3NxNWMg0PD8FRsB+9/Httyx4mAvhgrNRAZ5zALWLXfEVd+VoTs80kYmzgsQR8vrlPk+RTYh6Opgosgm0mr2EpihyxhWYTQnduL29HhBzLMd2mI1RBQpOBQDzJP1S0iXyiyTBykAhOPaIpRNCnEqd0CakkGSaf7goVpzQv5K7KEYQYc0ugZCuhIDSCffMkyCCg4nJe5AGhvzjSDGCzKLLGlgdYFy10FaPpyUfkTYOsiUQxQhFRTAgAmgwJwxaf0cYKDCGrAM87MNNtDwuQDSr4Gq3AsX2AbShGwfZKuR8X4xFSkSgu0wO/x4JeM2+Eo4W0TdscCHj+4Rt8Ma6icBpbQ3khhRGvIlHsFixUAJJAw4jCSsZA96Hho4dpHCVhBcANMg2QORHVHOuTUl642ELFGjOg/EMU7mPpfwIac6s94AjNo8MGwR0d6kpXfXSkKQinMWZx8kHulb9slKFiICwKgJFKtAg7j6qLQhjwqZIO0HS2hVUzQf1PIj/MJloOawGkg6Zp7AeaKi9cP4DRiAeBkW5pYHIjQKYQIPAAISKNEqUOsfHXQDpZkuW4HFfdWD5QkN6LrdinC0t75QDWRXwEbClpWAjohJAMuhd7wyC9QgPwI4i8hHYICh5ArRJTBt8AtcDnV6mKDUzUcA/CawLivVB7Xd8EGJKcKEwehFyphVDYQ8aoS0v5ivSx4ftBHB4GdnLOQmTpvQkxLD5BCQaydY+QaTvkKj4fSRQYRxkCjggjgLBijCZQI73Mjlywu1DWAiKrj6DES2XE9QrNn2BBNWpGR5MCQNdkHFKQsJgVHIaxhETHQ/iRcTiccKxJOKy5i3WcUZxBIJxiLjbwYJcOyVGfEpPD4zw6DJ+gbnXNATraqv+0iPMLuOQA4DSdOjB2Lh5c5gPOxjUf5lMHerbp4MzCJaK3Q/QErPs9UouYhLQ2Blp7tLlaEGjqQGQmECk5BWA1UTM5i/MbMXCQuETYGsPYKPEIYMC3fZ28UBRHTpMzhpwlCLFZQ/gfR3vWAMVlAXRE6DIT3xINA1cTt4dky30p2sdGR4C1JooeJKVjJSiljbPGuUEgQ1L67REDJ8EwQIQDy/SOcn2tFtsaO4HEAM9iOaFqmm4kwozNGYQC5gC98yeTxvw4hCmD2VKHe6RWxFkAJt+80nHUF/i/QnrlaUOlF/5cEcg+EWJHYbqs5sswxyVnTgHUyMigmK+AbMJNUhM3IWnCsg9IEv+gIbhxx7TTnKfDy78G/Il2AxVfiqdxgVQ9k2Eub5Q0sWCHyw8ijBoEeUHuIPGmT9feamAkwboxiDXxBnwGkUh6Ak1BPSNRE9AYm78Jp1NuB9wUHyyFibJpEPNCfBP6qLJ4KQSuHBWyKfB15kKLTJs7xaXkopOOmxRPfEGhPK4l/MufLRlKw+QNoQ72YIVw5CyOWA1IBi3BJTEYzi49KuyGS08TbVM1o1VezwvV66+HCrE7lhULkN8K/QFMs/ySs8SEoq/tcs+PJMIgviEYyTmIbcU0QFyMWFNrF70da+sXeUJmuGLGze4RGR5rsi/5bsoIGIACKq5pJqDKOjYs9GlxVwhBt2SW1FIvyISEceowPQRxAYswe4YL5UqoYiAW+CghXkebgXUQyEk9IZXz4udoIoUl2TgXp4BXNGDrvBrCNVOtEdXsaRBCgW5DIJKHOuMuvIWBj0h1K/QYQ5aLvD3n4M8hDNWxwCtm/cMZEXH4kgHI5ENXnBxeFHOAnZES8k8Mpk+JXg0b/Ds+ATVwCsYbPQ7+eUx6JkNW5kpIkEEXwUggKgrD0g5LaNOaeX3QYdFRX4HgBpQtcpxoViY51Qai+OYeKkh8IiMlocVQJPQXAWGXu3UBl7B1Mi6pFOL14sf+a04TJEj0Lrc2GVzw78IJDxAMJ3xAVqGOyQnEAZztixOxhRZNiRoPCSf+iaXLAQaHdJCsUcNO3hfmVKyqqDgJlXm0FkIQ4mGg42AV6QiJcDB3wqAFXK7A5BAHljjKFS3NWASTKAD8Vd1P4Au2GHxNfOggOsgCJ4NxD0I4GmpQ9Dp9TtUF+kFALjIjcIWg0duCBC+Ykr1g6sgwe6YEREwU4JRsoww6gDRah4AMSTw310lkMSAzgELXisqznhxwqKbHNrBHJDGJXYINuCQEG42zg83LnN0JAYGTQkUJWxWA2cxwShxRmuhNHmh2BB5gzzg9NArCNbsT9YVXk9IsgQhjdCMFUbLD14bY2iVNAGghzkMDFVYA0gsC4W4BbNJ/TWR7hpgBr7BaeWHF1ZxyJFYPvICiKu0MMNF4rpZB6xBQxO6mQhGAFBVQ2A694QKBByVuUf3YZU8IoRV7r4axMkTAEzndPzMVICWSArCVjyZp1TIIUR2ZiDzYIR1hOyZboi3hLfD62nAwkiBRNsp7AuYCPeg5FHjEQGfslr5NDyLd2mEgxmaUCf8VTSEf08sjsEdn9BnkTX0C9zVZ+NBaM6z4b5T+A8onfIHACbF7Q40DxgsPj4SlgXN9HRcGVRPAukr5BW+x1trLMidhQljihLJH0ZhBRLBnSBRIO1lsvAm6BzHPC1d7oCDGiBpB7xvkqGAIOwx7qgOcEwxgyTSA0l2efBk0rk+wg/M+kOHch3iyziX8pqTATpUNIjpLmHPgZ2EFLjEvvoHOQN0rnD7FdbsfE6BClgBklubZtguAYQTPKBwGiqxjQBq89/bWQFIgiuC89rdp4ZmslwKnzmrqHXWADEdC5QPRZcdV+UFyoC1YKaBoJRsag/Jm/h0U8V6GBXD2BN1BHpZD9TL/qO5G5Q/SioxJNYHqYBwVaUSsoWpJKqPpPptskPMhVNCr/K/KBMHWyBs2vabZf3VEwGAga0RXrI4qrkpI3bvVTxPajNe64MdlflsCEDGyAeXfExEOTYLxAR0uJm58JlHZi5X+xu5DsZxjBE7tp2ZRQHITcWA9YQ/HAe8uG/pcIqclaVfXKJKCOC+tMxT7owO9XzIBbkqx8hTOmWUMHuzT2Y7C5sVg1H2bfRTzys1FBSkTPPT2nVUG/42SZpNPXvbbmAeV3CGpNDZN+mIm4P2gkZFetUWTCuzPLBroUbkitBUgBnCU4UbfYndNsMU9vk5A3cOd20OGseKSXQZ2uPOj2TfciBq9Gh3PgFsBbUaMVgMTNJtuZs6UEUx0VKSvopIzCKLCw6BdPNN9LGadbMbHMPfDB4TLogeG60qf3A3LXzwHUivEd05ORIjl7CF20/zslibSRlZZ0iLqEx1iJaqB1fBO4ehfa6pooek/ssYHF4hKMULeSN6ph35HwS/n0Dy7Nh7lVlVymQa4LAhDWRBpOmt/thfkv+lOLm22x4lwIlN4+DdVmogUyiAItanFcIhXVhUBWjkbeY3E5IobhxF32hwhARGVP/0cEQ66c85YNpGojhrULrBpYQt5Av5rxpfAmpDeMCp6UEkKSpAUU9IUAAocIdrqVURlk8CTE8JVEYmeg/BMyZf7giwoSVwXyEKmnI6gG1hk7m6jaYgURGseZRiKMSE3YS8qp8D4N04UkRuuK3QaSQm3ASmYypmq9JBxmAIYIVFAuISUlQqATFgiJQadmwitgBzATWCzTB/CXPZ0hu5ABfVnVDu4HazOnEGQMAIszwdzX1BtnUGJFlA0MGD6aLVy3ara5CBgBi6WHATr9cqixkVFsKlAkYEs5Ec6ria4QLASDbWnEnCXmDIFChTk0r8DvBZRu6uwSFw+Ip/huCJWB9kfzaVUIy8CRXlUGse2QpopFsdWQBoJAHCTFEg+MVh8Z1jDdoR3JWxAVOP+zlgWGUa8Z4ECT1KopmASALujncCbjCc8TsIA82cKvQcVEGLfovQ0VIbMhVzmdw5SPJPqTlVI9D1YBvEk1guWp/cHfIKF5txLqsBgRMDKyekurGtkASplz7Q9vO2pgE8mCrpoDVQsigDD7SX1sW6hrgeYaTnqky6JgXZBhIBT407X9ulA0O/RU1JyCkTZdyO0IT07FRp8SodlgD8sayg913JSPaq+Uu2LQqCVREuYQNqIuYTtYAz1EaTApUgPoJDQRc48xAKO1SqkcLcr0qfON8TwOpDvQO5lVEdAoZ8iEH5O/xZ6QDkr2JTQmwI/BV4ZkQc18bNZPYzQgeFqeqfgdUbYaunSXtJ1UilQictiYTAT7kt3t0pn/FFJyTe9K8IU0QGzwrGYJswZ4lbX72iMbCry3VtA6BgqrJMshLqX4CQf7YgJBzP+3Aq7iWVA8DNbWdvTFqCVepeqV2F2DXS4RIWQK522eZKHw/grmbU7yq3tAa8jtp7yNvSSgSduBZobEi5SCR2RlZFbjOVzkg9IG7hbJtKBmHPC139Mu9Elx0xdz8n5A1Y0nISP0d3H0GtyrPavVQUP8Xc1DeHqTKWg4aXnLMmFgjbcFqkFeVu9cfBdyf0/ZSf9xE1XXcxGXW9kHbp6MqwEzSi9sx57AsvioP37u2lQhdmBJ3kDaMi5Nm+EXuQG1uuN0IAp/PSBBUR5scZUyX516YbgQqw0Qe7bdBqISAsw2ehicQ1EMDC8rHKO59eYqU+Ouru8yENyO+YiP9VQBE1DHwAQ+uAvUe1g0UTLMrNe5CZGGHI7StLa5+YMI2hgOyVW8eP3UlIhj5X7lF1gmRiqBg0ZJqPsi7Ffen3qPOCx5bkX0REWrykK1kabUVAL9ihfjIwmZAFP4a7Atd4J4i0h1dsLQ/QLYAiHxUT8B84rKBD7ydWr+aihCSwCokW4V+kB5oHOwvYgkp2ckdv1FrGzk4cc4EgKyAlZQcXtVHZBNZBGh8asHEuqZbdV9osW5WLB2uyQPqGftCKczPPKu58W3eOP8pcmlDALdel+KVGJTj5sYgaUXy8HsOFRUFm+iCoTI1ffuerypq/PTAZgWVmD3+iYVPqnqiq9QuIxpKNwFJxjhTI2yHlC4WZ6qmLrm0Hzu3Wq67eF0Eq1A1IVSaR1+b6ocwxtVUV2i8CJBQkOSzeghUAkIZt9ikGVs96yQ3D3hO+DftDDM9zCIC8Q4GduGPQMJC9jyszDorevd8/RNEZy+bVQUrBCyu7MF1lWXkxo+uDNWwRVmLzF7a2EZSYGDwWorPQMJvRYuaAXDnQjj3II4hI7KZ5fmRsNyLcQRTbQFChU8tHKTSDLG1yzIuVRQjCbF4BuahePdqgCAtj4LhQ10j/CVEbtbnNojH3Cauj8JIKnEuNVoimiA0lSyxmgjyWZyESheFc5GkPWK00UG7f+1xR3UmAU7YJ1zs7FG7mZojsJ9V0RqNt0ZO1QBMwiyi0KytBCBEVREEMNmZe1OvyYD4hjAS7PVH29BVjUvdPtflqu6Xy14Z3fZ8b9UuoXjs7Wrgz/23KhxCt6O2gyPrQUQprxARWh8iEKSc2nhVJzerhIoXfmGOHtQyGal8qoqMqKm+SxRVFBhTsSJQiw7ACt6sfjBkQwyzCyqeq518gyki6FVPOHNkwb429rox8Q15ZDkxtXdFXHbP2oM+BL9q18ZClZeGOQhOxuN+dBnSwJS+MBN0JDbRNqhyAEGqR1Ow5vC4IooySGvcdlY7DAIf3U2Uj/a+nxOhAsVufH7ShnVHLFdIFSHrBlcGk4EJkqBKuDTGVzN5QW55WHrzYPhE1PpSbQQekg4BB17hBG7BarbXEkN6gZ7wDYJf+QWxtAizoJlAVORFv2pp53ZFFWSJ/qsOqe9tKqg/gEdlEaUYQb4f8KALZRgfkMwn2/ARBRTJqiqD7xBxR3CoqFTUe4KixfFxW1fDS+f9gh4IBj4gSbXdITgwMG0C9Ef7gvJN6HCcyFCP3lGJShIfRS+EFD6G+SPawON/AydIX26ktNrPqDSy6vpEZpo2tJzqf6qr/NKFgVnjSR/y/Q3wkZ4CfOVU2uQUqnRGt8hiPMDwDWdyPECR1Q99VopqMJEYI6kGvhIlgZNNquxDEGQEoI4Bweh2ZIJjBSvPoPI6PiXjqlHnEoD4Axg+fmSIAIwVSgfFMNUQSCDUAKovPlYlAB2qoSl4YtEe2vFoUoEWAqpgbKWl/pJWtusrO3PNzo+q2Qg7iMVhZK6fiyJKrHc2iRkYQh3FeGce2utYynwtQsYibAUdCqC/RMbY3JtVcFVDgPugyW9g8oGoXL+nc1QMdB6f2cyqP9U3mxPd8GbzALU4OxXVvjHqT+z7gJQV0RqqN/8tSnn3/Qc859TZD3xAlHPTDg0uF14OYcrxgLu40lgEIkhFNNtV+QU6QfVMc7gf1Ado1jPDPGk+GpL7NVnI7mdjCJunIY6HaYsDyZy0OywzB0MUFRavU2H1NcMhnLdCbp6hlEFR4PxUXNkaDovIaLSh8h5fAsNeTfJoujCbDh8hXamysnaUN8SFxCKafQ3MZWJ2AZocLzL+aV5VvPS1/Yob7mfg0C59WL4DVKY4PjNWQACLL80dDxS2r3a5msf9IuFZ1sq9EATdqfe7a9N+Y3bAVcBYnzkweLxScmrH4Gqd5F9PV85yj6rBTwHwEdLfekCxpbcdvxfgg0bisaEZUgFcwdAlmWCFTNd2TSwPLLb/s43Gff5gQ61qUThdJaK5n2A8e20h3BA/y9HV0HWh4Q+C41jVrlKfX3D/DiVeWD/m3Twm5vHDvPIPoIKYN/kXL9ED8MMcSqn+hRLIcVX+SfpDXF7m5FXrQGjEyXoiAy0Op6hWhfdJSiQU8SJFbHnt4H4K1QjGL5XDj6Nf29eOZVElvKv5kGf3iMeRWf8gyjU1VPkDsKES1M/KZN83ka/ClzGk+QDC6oGCTQwRipVcr0GvsAhxVd83nAYZ+eWbex2NavD3oBBiitXUgYL6wg2Y+zD/fhS+heky7O//nhZ8E72nxChiUG0yf1m4XxwcPrd61dWl0CPMOV6lgbmL7UfRQV/d9x9+/oovj9r8qp34e2dydJZETh1bF6CQoS1LBTKegrhR8ddBW+AVLAWzZrX1/X7Vf/P1W19/s4z7OYCSGFa9PKC9ugdJOYiASURVA88Hfo7vjI6aHoE1NCTO6lQ7oTtNDDLngUNRY5om18dS1Dr/sPkVDj96SSPA3v5ETyr5ZmInutRNLJPFb0vFFdhFQEgEWcah4K8NlQaN9jswRV8l4Ql7/whYpGDiQhlT8lUhvmCOBFioKtv3sNRjkCXac1xNPPhEe1bj3iX2kXSfT3ouhNQ/2kpK6vZWjI6gQgQTk7VfK3w5Yg+VsKLKsETiUfPn6QbJDuBY22POqzLaZbJV9vODECQrmjalQRBfbXo1nl8QPD9FvP+ebdyjMSTcVmlBTI9F3J04/Kq6sE7lu+rS1C0HIKr3/vfYdz8Ffy2ANKwKiIKK6SNJq7ee/8Sx378CIzw4CeARXwrKsOWJ2vL/NDD/vfEL6poF42T8shoSShsgN8Yv6ajAGlPW/mifeYrX6tLTRx5KjT0/ovMTm4pMK/3pkE+xXp0MwpBPsV77u/NTrHeXy6rZIKDonh2EN1gdA+TvVPkEbPxE1kxLxykUWbGp9Ter+VJNJkRWY/nz82481KfKlfjkJ7K2jpCoOxohMLQhTr5HRdZkKHyOyGoA23mg6rrlkYjNU75E1MdZfoX6TsmaxLtp4yDHPdQjjUFVZQrI6Bu9qH5reC2SeoXAe1Td1JzwKlGfZM2fAyeyFj/Xon6tRKkOtd07/YGf1b4J987wA9EQydZ37mSXMmNgfibeSXVee31kEqI1/Fzhcr+XuFThSgP2xwb8EpX1f47KV9Kw/w9R6b4p98+4fLIIzmD2n3ZRU99patX99B39ZQ9erq36lWtRPWVVHdpSlEfd89DOjH6o+2CMzhPW5SFgbIYmCcMlZa8qJDHoPkGI+dq1RYL8yGl+Id8FOAl4VAQmOKk8KjRvOmeog31kPnEbXtt6ZY60x3Czeo4RO8kfyOZTOO2mbTQMGauGO9D+WyqGpww6TbE7rlbjAT3xzA6Dg6z+VFyBYT+hETBbwpEngOF02ARvBfgS1l1HN9Pbc4HyRM+vCxK0dyo9dql87AaBOjPirySUJkoGsF8HCeKRzeBuJ1VxJadLE8fPzl2BmUG8ldwJgzsl7aX7T8thlb2eYjH11XBTL2WqRmi17qtonndZoyC6vMrRUycnVNKIW1ssXlVzEtsvQ0Bq+7Bq57bVsIIq6EGVGLKwq0aawJKr2hZxxwz24btOr/IwVQclUnt7w6gl01mmVhIoErHY8ACrvaKquTrvh5Oo3IaHNsa0mIQ03DIYkAfVySzcOTrStCeujZyLimCl1FIPtUpMqJf4qT2ECda2g5hqmSgfT+t/GJO/vm51R8ztP42KqrGyOEz5nzXaH7Va/qDEJpVJ2CKkVWeTumpELzrWQeR9euwIG+Y7ex1FycQ5YDfq6WHoZJTDJg+FTYbb1HgNyg05dHRXA9zABSlyJvuqXJNkcxecelSeQEvifaDY25F+2vSuU9396EXJYNZi7KGScGir6kyqCsEfq77X2x6JHVPExZrarDFH4KiTUzSVjVpXDQJX0QkRHdqcxbSd76Npew2ykZCu2pknuoKqFChc5hyZs85xKnIP8UhXc86AeTD82BQ1Cs/MT2qTcaQ2F8ned8A1ItYljU8gM31+Hw3myBuAPRwyl0cuXb062vwpnuBuqvK/hnjt5qlBKuhY9BkHq4hQZLphQ57dtlu9fPVdya3BR1/b6AKDrnYmHhhh823T1TQSIgtWe9K34U+m1yrGD8latbfTdMSOQeo0WVgnawu+61SgLoEwOuoDv9pims/OghpdnTRZJ2rrcFsHjcVQYcqJqfgGWpOT+J78XtlACGlXxbrOChDWeDWwr2Wt3p5nIfgwbA7r0ju227ZivpMH6s5AFQU1qSxLAq+tFjL4Ek3qVeLXEKzyBUipYErx2VldzHlWYxOo1SyaelaAPLtPX3R1U+LahUZbrTHZa99tCPfiVVhnAHd1nYXoZaiWH9QRW67IH1Oh/lHiZu4PiTNVaj/mMYZq61v9/eDK7m2quzomh82MCfZUY2g17WrjFA+hqcPYJWFZ50R2lCqPhudF7BVBw5kV2xdVt9ZbKGAR8w8c1pMJqatl5a0xs54jDhvYqzepvkIq1giUWtZ2EuJFwl8tJurbUPbnE5UXUiWjz35T3IuIBI/zQZNsNZMhmWFOwpgrAZ/65VVxBw8HY8zb6YANptt/YW3YC9iC+sHYbiTDCSyAdmAa2QUmfED0gnph61hhPPVW8NSB3lnHVbMODWGJtROh9CEYe9I+lOcZdb58jA1PCfyuID2qBxq9rpNVOdfohljOF9hmeLXuITc9wfMPwVIvCiCidxx8LCYdLUIavWaNKjBAboTGcqtr9BjqHVE0rcnyATVzdBW3qzZb8f1zxu3neb0Ph1RhgU0NWcjMG9GUVU2nF11QdKhVLkJV/r0jEuPtjmn3cyxnPmqHquj0xRRU17TeYd4OkeHAo9okEA/HH1W+io4cErxoi0m4MJEqmwAZTPbtOkkHyiqgNdmTkH/nKVgp0UJV1WT6Dy1wxdbs0UJVq4pQR62urgPupWt/nAlkamXamW+EA3pHTkz93CDm27XA7ISqtpd8KtpL/WsHDyWz5NJ6wPPpQdLeK3ZSHQWmHg+V+2KP7zz2rCEl7iYjh7/NNbSq177sxmonFRBAGlP/2WbKdHjgiZsVJMSnoBvGVnlcIEeiogZZ3UFI8iCvwkKmqo+tC4SJTL5LqmaEFWmuY1vCfzQT+JdhEnXEIf5IRFR8ySnMOFq5R69N8DINTt3aWSdvdC75C7Z0XtqCDv0EHclTM3vFoTQVoqa6nngkpBT6LCBMjnoNm1M9g0fBE+BMbKrJ5DS8eFdv6uxL5zwT2m1PdZMHEhv0xNywsnobCzN/dDKJyM7fxZ6vRvWI4Nl68F9Ovc7vjIAilLcoRZ1tjhVJKqyP7iAMtIm7fNYJILXjkAasPPr2NfSih1URIQB1QAWTj6q/CqyLWL0Efn897a57nXnEN6/LH3yK9rZTtN3oEXjEgVwbSjYjpKbOP2LBwfcbmYtRl/aS1ZjnZMazzzLz6uxUKzepwBJo98C//k01ZACQoMlByuHqmWxU8X1TjiD1C250pZznTUk2Y610uHWoL1edQsiRzWCrDtCAGyCiGkdBWZi1CG5NZ879a0V2RVUzngxY1ArlsnzTmVmQI9d9DSmh9mtymI+/1wnpjIXWPOtA0AJUdQo2YbMmyKmjpziFUnUgDaA+SILkFdIzvMOc73ztkpbVOz1Yk6MuZjl12BEYylxog1dkDwsvV4OH1MEfdBBeLOsM2vFdoyN+3xBVYGKCdVw+cQc4cRMS0U1QCOnAcqpSHFAfcHz0qjFGHYcDfuBtcgim2Ur8EdWurS5nHfsQ3wW8ynVTpV9yKTB/oHrOXwdDSAu9MYTABZeQeRFYwTgBFOiD9TYqUT8DjY8H57PqrCN8dKIXmiumAEAI5X5fubxthk8Ao0n0rhG0V74FbUT4qlknBxQBc6+KVn8vAyC/oigR9oWSQJTydtzeiyKkpjZ6gB/DCtarTfTDisxaFpDW1XJy8P0ga0mbrPCfjUqysdjDE3j7HvAtCGyDDqupTZH0al2VAqhGRwixL2r9c1e+n8xdfZHaTa9rUAOfiZ5VXhvqot4HXrc/iC2p6hoGOidMbR7UwjLGe0fQZGojDSZbiyCGZbmxnJpO1iT1momGqnCryzGpeYmQ0DY9OQRDAp/XPs1Hqg8wffwVIVIJjqCmRK8ujXFWu+k1f+mhEVlTXRpNxyyd2rtxAVxHGk97r9rmkbjaPOvVuW6l7GBmTNEWmWOUNiGSdf+sBjC1ljnTiVO9ekYHiaysr60KGfcIOS+CjYRg+GQZCh67toRaOgBpxBkuBOte13ZqCIhN4oNnRkF9mjTy2+6MgE9WiRRvTbyofdCWTtIjZ7cECgJAtXMif7q9OiCCyO83iIu22iXFkllV2P3qw+jVq/dBDFWi9B4kmEcvqRKLv/MrY0zHPdXyjefCfZkOcoEhpCMCok+9sUQv+BFO6L1vOgqa9Z4RvVOCEZJfIM8wa9PpANeZ73ia1xlKgL0zl1xhlZrR8bfahCeAA7HrIxPpTtNWEHoIDI1Mb3TakVx6nYZ2r6xEvbSCNTb0P96i+E7GJ53wIO6B1avT5kWv9LnfWIiJA/VdFRgCdBOkIaJKCvEd6INBuTZEMvXCEZ3j1clPfzoxpJcTkZo61eW1rY3M89o7whXhD6DzoPhZ2pxWwztcmXXiyPTaIlNtaOsywJ864qGQrTMTWCR+dphOiteM5YQz4Al1wDUpX2T2ow6vcx9LLXrYRDyYGs+v/GXqqgkoG0RPUHZD1arsMvt4B8L0/gYmY5/1VfpCfL9DYl/vnvBfJ7Q/5usvSer+MPBXZ2xMNeqdWX/R8sDLoytJCQh6zK6XA4iMYcOsvTAdOXBrb9XqCe2mMpKop6CHuzKgip51mE6twk1ddk3vi1CrMUIBymClj3pvZPxk8/SWBBWEXldk0ObxlVfFYsKJqh8B4NipKRP5Tlthk5G0ByYaQwYaV8KIPuVzwjL3Bk6p8VuKIUf1CL7mR35Ab5naiHuQXieUUc8YFb24gEESWX44NHRWxyY0qBJL3LA6v3f/jMQ7battL5s9XTgotPdKxKUk77gnyBuXgJJzdX+xhRr4r+2kfZahznboRa1ZRKlOwhJtE8BEGQXtYxw1h2+9oiqR8WVvVi3KcE+dbyPYtFePUfKgvGyk6aBAUF2E8auNAUGIPn0H8HF1y8vVAFiwSPJ3d53Mi4ZC8jXp+Gv/iA3Nhg5QqqtWHJmuNh5lN2pCmEudLO2+IfeDW1EH+NHdVx0yJLo+Cm8VLqmyelcljoQjLJaWDI0BnOg0LthNShLf2iIcTgoVUcXAtIn7Om24mRpMdZRFR620m663r2j/gmdQRSsBgWJDNaf49w6P6NT88grROPLVM7hUtXO8dCyoqn3m6M0CrOzRC8NM0VV01v/HiyDiIymgtvf615sg9vb+6nyb2v3JDWz+1kvHsDRYlKPXAS29ukVvf1LRrgvIUUJXfbVTL1fprfq98m4pPmeiFlVt196gY146Yg3EiluQJVP9RJg4vQ2BBVkVk4cVhTMMpSJbzEXU1sSjJwBXW7wm36oCPgGPE9+kLYqBRIvStaCX2hSPYgdZQ/DpFE2A6i8TqrcSbm1d6LgLZrgjsBoqDAEVP8EuH7STivVNTvBKMh2H61OEYVBeymrjsr7+m1fwPjqYGdVSGuCKFceDSb1NxNRZXHQMRm3bZzggovlXLSKTGYtKw8jVo1eXvbMwqbNKWJqjV6DhNgo0gq7Jl5nXW2oubm7s5UbGHK/k8Us4lKbqL5oY/QHofLaT1ZLe/+OBSPcwE0VWgQXm77tBKYOqfxRMH9jGV0H7Okqp4+/+t3aP//lr0CYqfryxIBsXnbRjrrPC0Bn+LVUHgl4kAqImvC07b/cdZtFxd3hBXVF5f9X9w3uxitxglCfS++zqgqe7uli9f5s+4RlHvXIHYtLWBmuLyFAzsN6DoQ5L1dyBK7CEoelNYPvUBJlhJIkRd99rLb193m7JRI8lRydDBNgqa6apMfFO0+GnANgFnZUhm6YKNvDX1lEutyuSLevcXASmpQJQGPUJGkB/qu5Xem56wRl/O09VnVuv4YmHZ0DAbTHLhCC7DnUBXjqirm5JCWuRA2ZEh77Pa2SBSgjjt8FXtVc1ydM9ZNSqirCYQzenNhV1mGQW8Fva8HTJnOPX1KYEmhQKgIFyRgwA3zo+iA1g+ghb//li2Kyjl0+899RgIeKVhp6ExzHIq7z31PiTP80wemFNC4pTgBh9wdKzhF3dLMnpfEjVS43U4apciQMTvqSuCB+sEjwSSUt4Mf+1/aM25BcG8K26Ym8V0xIHpnPc/rWzvD7rKQRn8pI2lKxsAmqpXzM1ZGZQDY4F9nqNzRsrXOnae7/AWkx/ksEfTW9w+nTLSXXU9Z+3jVUvcN8n21E98BI5838AJYettzYz/GwAAAGEaUNDUElDQyBwcm9maWxlAAB4nH2RPUjDQBzFX1NFKVVBO4g4RKhOFkRFHKWKRbBQ2gqtOphc+gVNGpIUF0fBteDgx2LVwcVZVwdXQRD8AHF1cVJ0kRL/lxRaxHhw3I939x537wChXmaq2TEBqJplJGNRMZNdFbteISCAfoygV2KmHk8tpuE5vu7h4+tdhGd5n/tz9Cg5kwE+kXiO6YZFvEE8s2npnPeJQ6woKcTnxOMGXZD4keuyy2+cCw4LPDNkpJPzxCFisdDGchuzoqESTxOHFVWjfCHjssJ5i7NarrLmPfkLgzltJcV1msOIYQlxJCBCRhUllGEhQqtGiokk7Uc9/EOOP0EumVwlMHIsoAIVkuMH/4Pf3Zr5qUk3KRgFOl9s+2MU6NoFGjXb/j627cYJ4H8GrrSWv1IHZj9Jr7W08BHQtw1cXLc0eQ+43AEGn3TJkBzJT1PI54H3M/qmLDBwCwTW3N6a+zh9ANLU1fINcHAIjBUoe93j3d3tvf17ptnfD1I0cpoJlD0vAAANdmlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNC40LjAtRXhpdjIiPgogPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iCiAgICB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlRXZlbnQjIgogICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICAgeG1sbnM6R0lNUD0iaHR0cDovL3d3dy5naW1wLm9yZy94bXAvIgogICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iCiAgIHhtcE1NOkRvY3VtZW50SUQ9ImdpbXA6ZG9jaWQ6Z2ltcDo4ZDUxMzAzNy0xYTUxLTQ5Y2EtYTZjMS1hYjNjOTlhNTVmODIiCiAgIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NGI5ZmE4YWYtYzY5ZC00YmM4LWE2NDctMGM2NmUxNGViODU0IgogICB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6N2U3OThjODAtODA3YS00NzUwLTlhY2UtNzU5NjE1YmExOTA4IgogICBkYzpGb3JtYXQ9ImltYWdlL3BuZyIKICAgR0lNUDpBUEk9IjIuMCIKICAgR0lNUDpQbGF0Zm9ybT0iV2luZG93cyIKICAgR0lNUDpUaW1lU3RhbXA9IjE2NzYwNTQ2MDMxNzc5NzkiCiAgIEdJTVA6VmVyc2lvbj0iMi4xMC4zMiIKICAgdGlmZjpPcmllbnRhdGlvbj0iMSIKICAgeG1wOkNyZWF0b3JUb29sPSJHSU1QIDIuMTAiCiAgIHhtcDpNZXRhZGF0YURhdGU9IjIwMjM6MDI6MTBUMTQ6NDM6MjMtMDQ6MDAiCiAgIHhtcDpNb2RpZnlEYXRlPSIyMDIzOjAyOjEwVDE0OjQzOjIzLTA0OjAwIj4KICAgPHhtcE1NOkhpc3Rvcnk+CiAgICA8cmRmOlNlcT4KICAgICA8cmRmOmxpCiAgICAgIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiCiAgICAgIHN0RXZ0OmNoYW5nZWQ9Ii8iCiAgICAgIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6NWE0ODRmNjctNDY0ZC00ZDg3LTgxYTktYmFmOTQ2MjQwMmViIgogICAgICBzdEV2dDpzb2Z0d2FyZUFnZW50PSJHaW1wIDIuMTAgKFdpbmRvd3MpIgogICAgICBzdEV2dDp3aGVuPSIyMDIzLTAyLTEwVDE0OjQzOjIzIi8+CiAgICA8L3JkZjpTZXE+CiAgIDwveG1wTU06SGlzdG9yeT4KICA8L3JkZjpEZXNjcmlwdGlvbj4KIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAKPD94cGFja2V0IGVuZD0idyI/PgmblDYAAAAGYktHRAAAAAAAAPlDu38AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfnAgoSKxc46T0uAAAbEUlEQVR42u2deZRU1YGHf2+vrVeaHRG6lYCK4JxxzSTDosySGBWj2ZyJk9EcJWYijiCYM5lzcs4ExAhqEJAmambMxGwmk0zGJSKYRKNoxLhB090gO03v1bW+5d75o6q1XdCmu7rrVb3f9y9U1ev73v3qvXpf3QIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQUjrr184y69fMMjkRwUTgEwWPM+gV62tAujEbU2wAgmRJ3hB3vj503Pe1ydCgAUq7v+Pf8tZY2tbNDMes2wzIu81QZAgBNKBkn6/xPJpG9I2x7r3Z84xmPo0UBkHJ5x797vqqaOC0TCy2LWOoXhKZG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\";\n\nmsg.payload = default_image;\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 450,
"y": 1640,
"wires": [
[
"51b15b96b7068b55"
]
]
},
{
"id": "28bb787e0806b511",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "GCode_File",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "sensor.{HA_PRINTER_ENTITY_NAME}_gcode",
"state_type": "str",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "gcode_file",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 1230,
"y": 1540,
"wires": [
[
"9d7d34a6f1e19c23"
]
]
},
{
"id": "9d7d34a6f1e19c23",
"type": "function",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "Get Plate",
"func": "\nlet plate_name = msg.gcode_file;\nplate_name = plate_name.replace(\"/data/Metadata/\",\"\")\nplate_name = plate_name.replace(\".gcode\", \"\")\nlet plate_id = parseInt(plate_name.replace(\"plate_\", \"\"));\n\nmsg.plate_name = plate_name;\nmsg.plate_id = plate_id;\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1220,
"y": 1580,
"wires": [
[
"b45595cb76197d84"
]
]
},
{
"id": "f9cb0af2a6c85c49",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "Printer Name",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "sensor.{HA_PRINTER_ENTITY_NAME}_machine_name",
"state_type": "str",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "values.printer",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 1450,
"y": 1620,
"wires": [
[
"c0bfe664d33c9ff8"
]
]
},
{
"id": "c0bfe664d33c9ff8",
"type": "function",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "Format Msg",
"func": "msg.topic = \"print_preview\";\nmsg.machine_name = msg.values.printer;\nmsg.model = \"X1C\"\nmsg.machine_name = \"X1C_\" + msg.values.printer;\n\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1450,
"y": 1580,
"wires": [
[
"b8bc2487c25657b6"
]
]
},
{
"id": "b8bc2487c25657b6",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"x": 1360,
"y": 1520,
"wires": [
[
"dbb49f936e18c921",
"5cc053aff21113dc"
]
]
},
{
"id": "dbb49f936e18c921",
"type": "function",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "Printer Config",
"func": "let data = {};\nlet payload = {};\nlet device = {};\n\nfunction getFriendlyName(str) {\n var i, word = str.split('_');\n for (i = 0; i < word.length; i++) {\n word[i] = word[i].charAt(0).toUpperCase() + word[i].slice(1);\n }\n return word.join(' ');\n}\n\nlet printer_name = msg.machine_name;\n\nlet type = \"camera\";\nlet base_topic = \"homeassistant/\"+ type + \"/\" + msg.machine_name + \"/\" + msg.topic;\ndata.topic = base_topic + \"/config\";\npayload.name = getFriendlyName(msg.topic);\n\ndevice.identifiers = [];\ndevice.identifiers[0] = msg.machine_name;\n\ndevice.manufacturer = \"Bambu Labs\";\ndevice.name = msg.machine_name;\nif( msg.icon != undefined) {\n payload.icon = msg.icon\n}\n\npayload.device = device;\npayload.unique_id = msg.machine_name + \"_\" + msg.topic;\npayload.object_id = payload.unique_id;\n\nif (msg.device_class != undefined)\n payload.device_class = msg.device_class;\n\nif (msg.unit_of_measurement != undefined)\n payload.unit_of_measurement = msg.unit_of_measurement;\n\npayload.topic = base_topic + \"/image\";\npayload.json_attributes_topic = base_topic + \"/attr\";\npayload.image_encoding = \"b64\";\n\ndata.payload = payload;\n\ndata.qos = 1;\ndata.retain = true;\n\nnode.send(data);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1460,
"y": 1500,
"wires": [
[
"5b752e13e2378572"
]
]
},
{
"id": "5cc053aff21113dc",
"type": "function",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "Printer State",
"func": "if (msg.payload == undefined) {\n return;\n}\nmsg.topic = \"homeassistant/camera/\" + msg.machine_name + \"/\" + msg.topic + \"/image\";\n\nnode.send(msg);\n",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1450,
"y": 1540,
"wires": [
[
"5b752e13e2378572"
]
]
},
{
"id": "5b752e13e2378572",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"x": 1580,
"y": 1500,
"wires": [
[
"1d472ed6d3d7a576"
]
]
},
{
"id": "1d472ed6d3d7a576",
"type": "mqtt out",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "Home Assistant",
"topic": "",
"qos": "",
"retain": "",
"respTopic": "",
"contentType": "",
"userProps": "",
"correl": "",
"expiry": "",
"broker": "489094618c340eef",
"x": 1460,
"y": 1460,
"wires": []
},
{
"id": "81f2db0cf1fa2c74",
"type": "delay",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "",
"pauseType": "delay",
"timeout": "1",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"x": 1220,
"y": 1640,
"wires": [
[
"2fca17d4bcd36129"
]
]
},
{
"id": "2fca17d4bcd36129",
"type": "file in",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "Get image",
"filename": "/data/fetched/{PRINTER_NAME}/preview.png",
"filenameType": "str",
"format": "",
"chunk": false,
"sendError": false,
"encoding": "none",
"allProps": false,
"x": 1310,
"y": 1680,
"wires": [
[
"3f93ad8aa7db7110"
]
]
},
{
"id": "3f93ad8aa7db7110",
"type": "base64",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "",
"action": "str",
"property": "payload",
"x": 1480,
"y": 1680,
"wires": [
[
"f9cb0af2a6c85c49"
]
]
},
{
"id": "6aba4661dfa4c7e4",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "Printer Online?",
"property": "{PRINTER_NAME}_is_connected",
"propertyType": "global",
"rules": [
{
"t": "eq",
"v": "true",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 1,
"x": 460,
"y": 1460,
"wires": [
[
"7ab3301e83fc0590"
]
]
},
{
"id": "7ab3301e83fc0590",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "Is P1P Cloud?",
"property": "P1P_CLOUD_MODE",
"propertyType": "flow",
"rules": [
{
"t": "true"
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 2,
"x": 320,
"y": 1500,
"wires": [
[
"c4136d77d81c879f"
],
[
"9386d0cbbffcf90b"
]
]
},
{
"id": "cac1b7adf2c6d624",
"type": "mqtt in",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "Bambu X1C {PRINTER_NAME} Request",
"topic": "device/{PRINTER_SERIAL}/request",
"qos": "2",
"datatype": "json",
"broker": "{GENERATED_PRINTER_MQTT_ID}",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 480,
"y": 1760,
"wires": [
[
"0795430eee910585"
]
]
},
{
"id": "0795430eee910585",
"type": "json",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "",
"property": "payload.print",
"action": "obj",
"pretty": false,
"x": 570,
"y": 1800,
"wires": [
[
"c898859abbdf69b0"
]
]
},
{
"id": "c898859abbdf69b0",
"type": "function",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "Is Project URL Cloud?",
"func": "if (flow.get(\"P1P_CLOUDE_MODE\")) {\n if(msg.payload != undefined && msg.payload.print != undefined\n && msg.payload.print.command != undefined) {\n if(msg.payload.print.command == \"project_file\"\n && msg.payload.print.url != undefined\n && String(msg.payload.print.url).startsWith(\"http\") ){\n msg.url = msg.payload.print.url;\n delete msg.payload;\n node.send(msg);\n }\n }\n}",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 460,
"y": 1840,
"wires": [
[
"5599c7b710ac608a"
]
]
},
{
"id": "5599c7b710ac608a",
"type": "http request",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "",
"method": "GET",
"ret": "bin",
"paytoqs": "ignore",
"url": "",
"tls": "",
"persist": true,
"proxy": "",
"insecureHTTPParser": false,
"authType": "",
"senderr": false,
"headers": [],
"x": 650,
"y": 1840,
"wires": [
[
"4c3f9b3f821499d9"
]
]
},
{
"id": "a3f958f3add4c012",
"type": "file",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "Save File",
"filename": "filename",
"filenameType": "msg",
"appendNewline": true,
"createDir": true,
"overwriteFile": "true",
"encoding": "none",
"x": 1020,
"y": 1800,
"wires": [
[
"08bc28f30a164480"
]
]
},
{
"id": "4c3f9b3f821499d9",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "",
"property": "statusCode",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "200",
"vt": "num"
}
],
"checkall": "true",
"repair": false,
"outputs": 1,
"x": 730,
"y": 1800,
"wires": [
[
"26af41f2b243fd25"
]
]
},
{
"id": "08bc28f30a164480",
"type": "function",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "Set Msg",
"func": "let temp_msg = {\n \"localFilename\": \"/data/fetched/{PRINTER_NAME}/current_print.3mf\"\n};\n\nnode.send(temp_msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1040,
"y": 1840,
"wires": [
[
"629c07afdacaed2c"
]
]
},
{
"id": "26af41f2b243fd25",
"type": "change",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "Set FilePath",
"rules": [
{
"t": "set",
"p": "filename",
"pt": "msg",
"to": "/data/fetched/{PRINTER_NAME}/current_print.3mf",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 850,
"y": 1840,
"wires": [
[
"d656805d7bcdc699"
]
]
},
{
"id": "d656805d7bcdc699",
"type": "delay",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "",
"pauseType": "delay",
"timeout": "10",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"x": 880,
"y": 1800,
"wires": [
[
"a3f958f3add4c012"
]
]
},
{
"id": "f25d82ddb0337696",
"type": "delay",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "",
"pauseType": "delay",
"timeout": "2",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"x": 520,
"y": 1720,
"wires": [
[
"984eea7487453707"
]
]
},
{
"id": "c4136d77d81c879f",
"type": "delay",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "",
"pauseType": "delay",
"timeout": "35",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"x": 880,
"y": 1760,
"wires": [
[
"08bc28f30a164480"
]
]
},
{
"id": "d4849513cf0a8fba",
"type": "function",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "Extract Plate Json",
"func": "var f = null;\nif (msg.payload !== undefined && msg.payload.length > 0) {\n for (var file of msg.payload) {\n if (file.filename == \"Metadata/plate_\"+msg.plate_id+\".json\") {\n f = file.payload;\n break;\n }\n }\n}\n\nif (f !== null) {\n msg.payload = f;\n if(msg.req !== undefined) {\n msg.statusCode = 200;\n }\n node.send(msg);\n}",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1310,
"y": 1740,
"wires": [
[
"83b03ee855471ede"
]
]
},
{
"id": "83b03ee855471ede",
"type": "base64",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "",
"action": "",
"property": "payload",
"x": 1300,
"y": 1780,
"wires": [
[
"eb2bd4860f82f073"
]
]
},
{
"id": "eb2bd4860f82f073",
"type": "file",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "Write JSON",
"filename": "/data/fetched/{PRINTER_NAME}/plate.json",
"filenameType": "str",
"appendNewline": false,
"createDir": true,
"overwriteFile": "true",
"encoding": "base64",
"x": 1310,
"y": 1820,
"wires": [
[
"4df45cdd7a364fff"
]
],
"info": "This is a backup approach which writes \r\nthe file locally into the NR instance.\r\n\r\n"
},
{
"id": "4df45cdd7a364fff",
"type": "delay",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "",
"pauseType": "delay",
"timeout": "2",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"x": 1500,
"y": 1740,
"wires": [
[
"4e66dc111a31e102"
]
]
},
{
"id": "4e66dc111a31e102",
"type": "file in",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "",
"filename": "filename",
"filenameType": "msg",
"format": "utf8",
"chunk": false,
"sendError": false,
"encoding": "none",
"allProps": false,
"x": 1500,
"y": 1780,
"wires": [
[
"99b283650ac47d8d"
]
]
},
{
"id": "99b283650ac47d8d",
"type": "json",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "",
"property": "payload",
"action": "",
"pretty": false,
"x": 1510,
"y": 1820,
"wires": [
[
"98315ed3585697c4"
]
]
},
{
"id": "98315ed3585697c4",
"type": "function",
"z": "fbda6ab16491b918",
"g": "a8e16f2f7cd7ca58",
"name": "Extract Plate Type",
"func": "if (msg.payload != undefined && msg.payload.bed_type != undefined) {\n msg.payload = msg.payload.bed_type;\n node.send(msg);\n}",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1350,
"y": 1860,
"wires": [
[
"8d19d0768126d960",
"7a3e49eb01797119"
]
]
},
{
"id": "a3e765e96362759b",
"type": "group",
"z": "fbda6ab16491b918",
"name": "Postgres DB",
"style": {
"stroke": "#001f60",
"label": true,
"color": "#3f93cf"
},
"nodes": [
"c207be711ef10b6a",
"50ca810a9ab07205",
"ba7473069f371df8",
"8bf5c9135058acb6",
"db4a43d5d6631118",
"0a9e3064d68660c7",
"eee0dce21d4b91c2",
"bc135fef68caf1ed",
"dcf293279321a598",
"7ef27dfc5aaf648f",
"80fe10448625eade",
"417afcee7a04a0a2",
"7f6eec43ae3d2fa0",
"c0bd71c5f8c63191",
"fd7de145f90381e2",
"9f785ff8ae78f4c8",
"a59ef513683810a9",
"57ed2f101a692dae",
"b62ebcf18556c189",
"10eb08b1a1de7acb",
"061ba64419d1fe72",
"68f63aed66cbd5e3",
"6a4ba58e99355e4c",
"c5c99a5cfe9da632",
"1707d16455cba415",
"c07ce3f59a10aac7",
"9f2d2e2411d850db",
"7ede0a3eb2a13c94",
"c7c9f6fcbdd71a9f",
"6e251ea8ba446823",
"fa51361c222215dd",
"e733d198e61a5062",
"d46519a504a1341d",
"b6fef40e301e1d12",
"42e55fc5c9123c99",
"1d6f980a4979a67a",
"296c0a8fc5707ef3",
"89b6de093608e1bd",
"92b2983e6e80385e",
"3bea4a461a0c7c4b",
"0ed5db3a40ab601d",
"1c8bfea602263ae7",
"a3e69a85d5a875b8",
"7479721db2f16939",
"11d0416b41dbf117",
"29ce3287b0fc9101",
"b292c53d06fe5323",
"76b73ce6ce99d69d",
"239b69ba6de0f3b0",
"38891e797d89fde0",
"380607347779a3fa",
"8aaf33109eab123b",
"1927a157e503a89a",
"f292ef02b868a96d",
"ac28bca5d1b05769",
"2e90a12c29779bff",
"13ab87bca0a9499a",
"8d19d0768126d960",
"302a329fbabf8e92",
"94f08b2a34e68dd4"
],
"x": 234,
"y": 1959,
"w": 1432,
"h": 622
},
{
"id": "c207be711ef10b6a",
"type": "postgrestor",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Initialize",
"query": "ALTER TABLE IF EXISTS prints ADD COLUMN IF NOT EXISTS material varchar(10);\nALTER TABLE IF EXISTS prints ADD COLUMN IF NOT EXISTS plate_type varchar(15);\n\nCREATE TABLE IF NOT EXISTS prints (\n id SERIAL,\n start_epoch numeric PRIMARY KEY,\n printer varchar(25) NOT NULL,\n printer_serial varchar(20) NOT NULL,\n name varchar(75) NOT NULL,\n start_time timestamp DEFAULT (now() at time zone 'utc'),\n end_time timestamp,\n initial_kwh numeric DEFAULT 0.0,\n final_kwh numeric DEFAULT 0.0,\n kwh numeric GENERATED ALWAYS AS\n \t\t(\n case WHEN status = 'RUNNING' THEN 0.0\n ELSE final_kwh - initial_kwh\n end\n ) STORED,\n status varchar(10),\n electric_rate numeric NOT NULL,\n electric_cost numeric GENERATED ALWAYS AS ( \n case WHEN status = 'RUNNING' THEN 0.0\n ELSE ((electric_rate / 100) * (final_kwh - initial_kwh))\n end\n ) STORED,\n material_used numeric default 0.0,\n material_type varchar(10) default 'filament',\n material_price numeric default 0.0,\n material_cost numeric GENERATED ALWAYS AS (\n material_used * (material_price / 1000)\n ) STORED,\n material_description varchar(50),\n material varchar(10),\n plate_type varchar(15)\n);",
"postgresDB": "79ce3199b8eeaa1c",
"output": true,
"outputs": 1,
"x": 440,
"y": 2040,
"wires": [
[
"3bea4a461a0c7c4b"
]
]
},
{
"id": "50ca810a9ab07205",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Start Epoch",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 2,
"halt_if": "0",
"halt_if_type": "num",
"halt_if_compare": "is_not",
"entity_id": "sensor.{HA_PRINTER_ENTITY_NAME}_print_start_epoch",
"state_type": "num",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "values.start_epoch",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 950,
"y": 2040,
"wires": [
[
"ba7473069f371df8"
],
[
"29ce3287b0fc9101"
]
]
},
{
"id": "ba7473069f371df8",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Print Name",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "sensor.{HA_PRINTER_ENTITY_NAME}_subtask",
"state_type": "str",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "values.name",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 1270,
"y": 2080,
"wires": [
[
"8bf5c9135058acb6"
]
]
},
{
"id": "8bf5c9135058acb6",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Energy Rate",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "sensor.{HA_ELECTRIC_RATE_COST}",
"state_type": "num",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "values.electric_rate",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 1270,
"y": 2120,
"wires": [
[
"db4a43d5d6631118"
]
]
},
{
"id": "db4a43d5d6631118",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Printer Serial",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "sensor.{HA_PRINTER_ENTITY_NAME}_serial_number",
"state_type": "str",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "values.printer_serial",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 1270,
"y": 2160,
"wires": [
[
"0a9e3064d68660c7"
]
]
},
{
"id": "0a9e3064d68660c7",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Printer Name",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "sensor.{HA_PRINTER_ENTITY_NAME}_machine_name",
"state_type": "str",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "values.printer",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 1430,
"y": 2160,
"wires": [
[
"eee0dce21d4b91c2"
]
]
},
{
"id": "eee0dce21d4b91c2",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Print Status",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "sensor.{HA_PRINTER_ENTITY_NAME}_print_status",
"state_type": "str",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "values.status",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 1270,
"y": 2200,
"wires": [
[
"bc135fef68caf1ed"
]
]
},
{
"id": "bc135fef68caf1ed",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Initial Kwh",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "sensor.{HA_PRINTER_METER_PLUG_TOTAL_KWH}",
"state_type": "num",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "values.initial_kwh",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 1430,
"y": 2200,
"wires": [
[
"dcf293279321a598"
]
]
},
{
"id": "dcf293279321a598",
"type": "postgrestor",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Insert Initial",
"query": "INSERT INTO prints (\n start_epoch,\n printer,\n printer_serial,\n name,\n initial_kwh,\n status,\n electric_rate\n) VALUES (\n '{{msg.values.start_epoch}}',\n '{{msg.values.printer}}',\n '{{msg.values.printer_serial}}',\n '{{msg.values.name}}',\n '{{msg.values.initial_kwh}}',\n '{{msg.values.status}}',\n '{{msg.values.electric_rate}}'\n);",
"postgresDB": "79ce3199b8eeaa1c",
"output": true,
"outputs": 1,
"x": 1430,
"y": 2240,
"wires": [
[]
]
},
{
"id": "7ef27dfc5aaf648f",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Start Epoch",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 2,
"halt_if": "0",
"halt_if_type": "num",
"halt_if_compare": "is_not",
"entity_id": "sensor.{HA_PRINTER_ENTITY_NAME}_print_start_epoch",
"state_type": "num",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "values.start_epoch",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 370,
"y": 2260,
"wires": [
[
"80fe10448625eade"
],
[]
]
},
{
"id": "80fe10448625eade",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Print Status",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "sensor.{HA_PRINTER_ENTITY_NAME}_print_status",
"state_type": "str",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "values.status",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 370,
"y": 2300,
"wires": [
[
"c5c99a5cfe9da632"
]
]
},
{
"id": "417afcee7a04a0a2",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Final Kwh",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "sensor.{HA_PRINTER_METER_PLUG_TOTAL_KWH}",
"state_type": "num",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "values.final_kwh",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 360,
"y": 2340,
"wires": [
[
"7f6eec43ae3d2fa0"
]
]
},
{
"id": "7f6eec43ae3d2fa0",
"type": "postgrestor",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Insert Update",
"query": "UPDATE prints SET\n status = '{{msg.values.status}}',\n final_kwh = '{{msg.values.final_kwh}}',\n end_time = (now() at time zone 'utc')\nWHERE \n start_epoch = '{{msg.values.start_epoch}}';",
"postgresDB": "79ce3199b8eeaa1c",
"output": true,
"outputs": 1,
"x": 920,
"y": 2380,
"wires": [
[
"ac28bca5d1b05769"
]
]
},
{
"id": "c0bd71c5f8c63191",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Print Name",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "sensor.{HA_PRINTER_ENTITY_NAME}_subtask",
"state_type": "str",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "values.name",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 370,
"y": 2220,
"wires": [
[
"7ef27dfc5aaf648f"
]
]
},
{
"id": "fd7de145f90381e2",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Printer Name",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "sensor.{HA_PRINTER_ENTITY_NAME}_machine_name",
"state_type": "str",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "values.printer",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 370,
"y": 2180,
"wires": [
[
"c0bd71c5f8c63191"
]
]
},
{
"id": "9f785ff8ae78f4c8",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"x": 340,
"y": 2040,
"wires": [
[
"c207be711ef10b6a"
]
]
},
{
"id": "a59ef513683810a9",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"x": 260,
"y": 2100,
"wires": [
[
"fd7de145f90381e2",
"c7c9f6fcbdd71a9f"
]
]
},
{
"id": "57ed2f101a692dae",
"type": "delay",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "",
"pauseType": "delay",
"timeout": "1",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"x": 780,
"y": 2040,
"wires": [
[
"50ca810a9ab07205"
]
]
},
{
"id": "b62ebcf18556c189",
"type": "postgrestor",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Insert Energy Table",
"query": "CREATE TABLE IF NOT EXISTS energy_reading (\n id SERIAL,\n printer varchar(25) PRIMARY KEY,\n read_time timestamp DEFAULT (now() at time zone 'utc'),\n kwh numeric NOT NULL,\n electric_rate numeric NOT NULL,\n electric_cost numeric GENERATED ALWAYS AS ( \n case WHEN kwh = 0.0 THEN 0.0\n ELSE ((electric_rate / 100) * (kwh))\n end\n ) STORED\n);\nCOMMIT;\n\nINSERT INTO energy_reading (printer, kwh, electric_rate, read_time) VALUES (\n '{{msg.payload.printer}}',\n '{{msg.payload.kwh}}',\n '{{msg.payload.electric_rate}}',\n (now() at time zone 'utc')\n)\nON CONFLICT ON CONSTRAINT energy_reading_pkey\nDO UPDATE \n SET kwh = '{{msg.payload.kwh}}',\n electric_rate = '{{msg.payload.electric_rate}}',\n read_time = (now() at time zone 'utc')\n WHERE energy_reading.printer = '{{msg.payload.printer}}'; \n;",
"postgresDB": "79ce3199b8eeaa1c",
"output": true,
"outputs": 1,
"x": 550,
"y": 2480,
"wires": [
[]
]
},
{
"id": "10eb08b1a1de7acb",
"type": "inject",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "",
"props": [
{
"p": "payload.printer",
"v": "{PRINTER_NAME}",
"vt": "str"
}
],
"repeat": "60",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"x": 350,
"y": 2420,
"wires": [
[
"6a4ba58e99355e4c"
]
]
},
{
"id": "061ba64419d1fe72",
"type": "rbe",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "",
"func": "deadbandEq",
"gap": "0.001",
"start": "",
"inout": "in",
"septopics": false,
"property": "payload.kwh",
"topi": "topic",
"x": 640,
"y": 2420,
"wires": [
[
"68f63aed66cbd5e3"
]
]
},
{
"id": "68f63aed66cbd5e3",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Energy Rate",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "sensor.{HA_ELECTRIC_RATE_COST}",
"state_type": "num",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "payload.electric_rate",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 810,
"y": 2420,
"wires": [
[
"b62ebcf18556c189"
]
]
},
{
"id": "6a4ba58e99355e4c",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Kwh",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "sensor.{HA_PRINTER_METER_PLUG_TOTAL_KWH}",
"state_type": "num",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "payload.kwh",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 510,
"y": 2420,
"wires": [
[
"061ba64419d1fe72"
]
]
},
{
"id": "c5c99a5cfe9da632",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "RUN / PAUSE / OTHER",
"property": "values.status",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "RUNNING",
"vt": "str"
},
{
"t": "eq",
"v": "PAUSE",
"vt": "str"
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 3,
"x": 570,
"y": 2300,
"wires": [
[
"1707d16455cba415"
],
[
"1707d16455cba415"
],
[
"417afcee7a04a0a2"
]
]
},
{
"id": "1707d16455cba415",
"type": "postgrestor",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Insert Update",
"query": "UPDATE prints SET\n status = '{{msg.values.status}}'\nWHERE \n start_epoch = '{{msg.values.start_epoch}}';",
"postgresDB": "79ce3199b8eeaa1c",
"output": true,
"outputs": 1,
"x": 920,
"y": 2340,
"wires": [
[]
]
},
{
"id": "c07ce3f59a10aac7",
"type": "postgrestor",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Insert Update",
"query": "UPDATE prints SET\n material_used = '{{msg.payload.weight}}',\n material = '{{msg.payload.material}}'\nWHERE \n start_epoch = '{{msg.start_epoch}}';",
"postgresDB": "79ce3199b8eeaa1c",
"output": true,
"outputs": 1,
"x": 1260,
"y": 2040,
"wires": [
[]
]
},
{
"id": "9f2d2e2411d850db",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Start Epoch",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 2,
"halt_if": "0",
"halt_if_type": "num",
"halt_if_compare": "is_not",
"entity_id": "sensor.{HA_PRINTER_ENTITY_NAME}_print_start_epoch",
"state_type": "num",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "start_epoch",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 1250,
"y": 2000,
"wires": [
[
"c07ce3f59a10aac7"
],
[]
]
},
{
"id": "7ede0a3eb2a13c94",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Progress %",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "sensor.{HA_PRINTER_ENTITY_NAME}_print_progress",
"state_type": "num",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "progress",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
},
{
"property": "entity",
"propertyType": "msg",
"value": "",
"valueType": "entity"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 530,
"y": 2120,
"wires": [
[
"6e251ea8ba446823"
]
]
},
{
"id": "c7c9f6fcbdd71a9f",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "If Failed",
"property": "payload",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "FAILED",
"vt": "str"
},
{
"t": "eq",
"v": "FINISH",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 2,
"x": 380,
"y": 2120,
"wires": [
[
"7ede0a3eb2a13c94"
],
[]
]
},
{
"id": "6e251ea8ba446823",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Start Epoch",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 2,
"halt_if": "0",
"halt_if_type": "num",
"halt_if_compare": "is_not",
"entity_id": "sensor.{HA_PRINTER_ENTITY_NAME}_print_start_epoch",
"state_type": "num",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "start_epoch",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 690,
"y": 2120,
"wires": [
[
"e733d198e61a5062"
],
[]
]
},
{
"id": "fa51361c222215dd",
"type": "postgrestor",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Insert Update",
"query": "UPDATE prints SET\n material_used = '{{msg.payload}}' * ('{{msg.progress}}' / 100.0)\nWHERE \n start_epoch = '{{msg.start_epoch}}';",
"postgresDB": "79ce3199b8eeaa1c",
"output": true,
"outputs": 1,
"x": 760,
"y": 2200,
"wires": [
[
"ac28bca5d1b05769"
]
]
},
{
"id": "e733d198e61a5062",
"type": "postgrestor",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Get Material Used",
"query": "SELECt material_used FROM prints\nWHERE \n start_epoch = '{{msg.start_epoch}}';",
"postgresDB": "79ce3199b8eeaa1c",
"output": true,
"outputs": 1,
"x": 590,
"y": 2160,
"wires": [
[
"d46519a504a1341d"
]
]
},
{
"id": "d46519a504a1341d",
"type": "function",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Parse Amt",
"func": "msg.payload = parseFloat(msg.payload.rows[0].material_used);\n\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 570,
"y": 2200,
"wires": [
[
"fa51361c222215dd"
]
]
},
{
"id": "b6fef40e301e1d12",
"type": "postgrestor",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "PRE REV 36 SELECT",
"query": "select column_name, generation_expression\nfrom INFORMATION_SCHEMA.COLUMNS where table_name = 'prints' and generation_expression is not null\nand column_name in ('kwh', 'electric_cost');",
"postgresDB": "79ce3199b8eeaa1c",
"output": true,
"outputs": 1,
"x": 980,
"y": 2520,
"wires": [
[
"296c0a8fc5707ef3",
"11d0416b41dbf117"
]
]
},
{
"id": "42e55fc5c9123c99",
"type": "postgrestor",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "REV 36 UPDATE - electric_cost",
"query": "\nALTER TABLE IF EXISTS prints DROP COLUMN electric_cost;\nALTER TABLE IF EXISTS prints ADD COLUMN electric_cost numeric GENERATED ALWAYS AS ( \n case WHEN status = 'RUNNING' THEN 0.0\n ELSE ((electric_rate / 100) * (final_kwh - initial_kwh))\n end\n ) STORED;",
"postgresDB": "79ce3199b8eeaa1c",
"output": true,
"outputs": 1,
"x": 1410,
"y": 2480,
"wires": [
[]
]
},
{
"id": "1d6f980a4979a67a",
"type": "postgrestor",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "REV 36 UPDATE - kwh",
"query": "\n\nALTER TABLE IF EXISTS prints DROP COLUMN kwh;\nALTER TABLE IF EXISTS prints ADD COLUMN kwh numeric GENERATED ALWAYS AS\n \t\t(\n case WHEN status = 'RUNNING' THEN 0.0\n ELSE final_kwh - initial_kwh\n end\n ) STORED;\n",
"postgresDB": "79ce3199b8eeaa1c",
"output": true,
"outputs": 1,
"x": 1390,
"y": 2440,
"wires": [
[]
]
},
{
"id": "296c0a8fc5707ef3",
"type": "function",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Row Needs Update?",
"func": "let found = false;\nif(msg.payload != undefined && msg.payload.rows != undefined\n && msg.payload.rows.length > 0) {\n \n for (var row of msg.payload.rows) {\n if(!String(row.generation_expression).includes(\"RUNNING\")) {\n node.send({\"column\": row.column_name});\n found = true;\n }\n }\n}\nif(!found) {\n node.send({\"column\": \"none\"});\n}",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1200,
"y": 2520,
"wires": [
[
"7479721db2f16939"
]
]
},
{
"id": "89b6de093608e1bd",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "",
"property": "column",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "kwh",
"vt": "str"
},
{
"t": "eq",
"v": "electric_cost",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 2,
"x": 1210,
"y": 2440,
"wires": [
[
"1d6f980a4979a67a"
],
[
"42e55fc5c9123c99"
]
]
},
{
"id": "92b2983e6e80385e",
"type": "link in",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Link - Rev 36 DB Update",
"links": [],
"x": 835,
"y": 2520,
"wires": [
[
"b6fef40e301e1d12"
]
]
},
{
"id": "3bea4a461a0c7c4b",
"type": "link call",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "DB Update Rev 36",
"links": [
"92b2983e6e80385e"
],
"linkType": "static",
"timeout": "30",
"x": 610,
"y": 2040,
"wires": [
[
"57ed2f101a692dae"
]
]
},
{
"id": "0ed5db3a40ab601d",
"type": "delay",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "",
"pauseType": "delay",
"timeout": "3",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"x": 1520,
"y": 2540,
"wires": [
[
"1c8bfea602263ae7"
]
]
},
{
"id": "1c8bfea602263ae7",
"type": "link out",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "link out 1",
"mode": "return",
"links": [],
"x": 1615,
"y": 2520,
"wires": []
},
{
"id": "a3e69a85d5a875b8",
"type": "delay",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "",
"pauseType": "random",
"timeout": "3",
"timeoutUnits": "milliseconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "50",
"randomLast": "300",
"randomUnits": "milliseconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"x": 1200,
"y": 2480,
"wires": [
[
"89b6de093608e1bd"
]
]
},
{
"id": "7479721db2f16939",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "",
"property": "column",
"propertyType": "msg",
"rules": [
{
"t": "else"
},
{
"t": "eq",
"v": "none",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 2,
"x": 1370,
"y": 2520,
"wires": [
[
"a3e69a85d5a875b8"
],
[]
]
},
{
"id": "11d0416b41dbf117",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"x": 1100,
"y": 2540,
"wires": [
[
"0ed5db3a40ab601d"
]
]
},
{
"id": "29ce3287b0fc9101",
"type": "function",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Force start epoch",
"func": "msg.start_epoch = Math.round(Date.now() / 1000);\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 930,
"y": 2080,
"wires": [
[
"380607347779a3fa",
"8aaf33109eab123b"
]
]
},
{
"id": "b292c53d06fe5323",
"type": "mqtt out",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Home Assistant",
"topic": "",
"qos": "",
"retain": "",
"respTopic": "",
"contentType": "",
"userProps": "",
"correl": "",
"expiry": "",
"broker": "489094618c340eef",
"x": 1480,
"y": 2340,
"wires": []
},
{
"id": "76b73ce6ce99d69d",
"type": "function",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Set Topic",
"func": "msg.topic = \"print_start_epoch\";\nmsg.model = \"X1C\";\nmsg.machine_name = msg.model + \"_\" + msg.machine_name;\nmsg.payload = msg.start_epoch;\nnode.send(msg);\n\nif(msg.payload != 0) {\n flow.set(msg.machine_name+\"_forced_startepoch\", true);\n}\nelse {\n flow.set(msg.machine_name + \"_forced_startepoch\", false);\n}",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 940,
"y": 2160,
"wires": [
[
"1927a157e503a89a"
]
]
},
{
"id": "239b69ba6de0f3b0",
"type": "function",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Printer Config",
"func": "let data = {};\nlet payload = {};\nlet device = {};\n\nif(msg.payload == undefined && !msg.topic.includes(\"reset\")) {\n return;\n}\nlet type = \"sensor\";\nif (msg.topic.match(/time/)) {\n msg.icon = \"mdi:clock\";\n if(msg.topic.includes(\"_start_time\")){\n msg.icon = \"mdi:clock-start\";\n } \n else if (msg.topic.includes(\"_end_time\")) {\n msg.icon = \"mdi:clock-end\";\n }\n}\nfunction getFriendlyName(str) {\n var i, word = str.split('_');\n for (i = 0; i < word.length; i++) {\n word[i] = word[i].charAt(0).toUpperCase() + word[i].slice(1);\n }\n return word.join(' ');\n}\n\n\nlet base_topic = \"homeassistant/\"+ type + \"/\" + msg.machine_name + \"/\" + msg.topic;\ndata.topic = base_topic + \"/config\";\npayload.name = getFriendlyName(msg.topic);\n\ndevice.identifiers = [];\ndevice.identifiers[0] = msg.machine_name;\n\ndevice.manufacturer = \"Bambu Labs\";\ndevice.name = msg.machine_name;\n\nif( msg.icon != undefined) {\n payload.icon = msg.icon\n}\n\npayload.device = device;\npayload.unique_id = msg.machine_name + \"_\" + msg.topic;\npayload.object_id = payload.unique_id;\n\nif (msg.device_class != undefined)\n payload.device_class = msg.device_class;\n\nif (msg.unit_of_measurement != undefined)\n payload.unit_of_measurement = msg.unit_of_measurement;\n\npayload.state_topic = base_topic + \"/state\";\npayload.json_attributes_topic = base_topic + \"/attr\";\npayload.availability_topic = \"homeassistant/sensor/\"+msg.machine_name+\"/status/state\";\n\ndata.payload = payload;\n\ndata.qos = 1;\ndata.retain = true;\nif(data.topic.includes(\"homeassistant\")) {\n node.send(data);\n}",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1060,
"y": 2220,
"wires": [
[
"2e90a12c29779bff"
]
]
},
{
"id": "38891e797d89fde0",
"type": "function",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Printer State",
"func": "// Filter UoM from payload\nif (msg.payload == undefined) {\n return;\n}\nmsg.topic = \"homeassistant/sensor/\" + msg.machine_name + \"/\" + msg.topic + \"/state\";\n\nnode.send(msg);\n",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1050,
"y": 2260,
"wires": [
[
"2e90a12c29779bff"
]
]
},
{
"id": "380607347779a3fa",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Printer Name",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "sensor.{HA_PRINTER_ENTITY_NAME}_machine_name",
"state_type": "str",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "machine_name",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 950,
"y": 2120,
"wires": [
[
"76b73ce6ce99d69d"
]
]
},
{
"id": "8aaf33109eab123b",
"type": "delay",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "",
"pauseType": "delay",
"timeout": "3",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"x": 1120,
"y": 2080,
"wires": [
[
"ba7473069f371df8"
]
]
},
{
"id": "1927a157e503a89a",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"x": 940,
"y": 2200,
"wires": [
[
"239b69ba6de0f3b0",
"38891e797d89fde0"
]
]
},
{
"id": "f292ef02b868a96d",
"type": "function",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "If Start Forced Clear",
"func": "msg.model = \"X1C\";\nmsg.machine_name = msg.model + \"_\" + msg.machine_name;\nif(flow.get(msg.machine_name + \"_forced_startepoch\") == true) {\n msg.start_epoch = 0;\n node.send(msg);\n}\n",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 760,
"y": 2240,
"wires": [
[
"380607347779a3fa"
]
]
},
{
"id": "ac28bca5d1b05769",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Printer Name",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "sensor.{HA_PRINTER_ENTITY_NAME}_machine_name",
"state_type": "str",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "machine_name",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 570,
"y": 2240,
"wires": [
[
"f292ef02b868a96d"
]
]
},
{
"id": "2e90a12c29779bff",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"x": 1260,
"y": 2300,
"wires": [
[
"b292c53d06fe5323"
]
]
},
{
"id": "13ab87bca0a9499a",
"type": "delay",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "",
"pauseType": "delay",
"timeout": "4",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"x": 1120,
"y": 2000,
"wires": [
[
"9f2d2e2411d850db"
]
]
},
{
"id": "8d19d0768126d960",
"type": "delay",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "",
"pauseType": "delay",
"timeout": "5",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"x": 1440,
"y": 2000,
"wires": [
[
"302a329fbabf8e92"
]
]
},
{
"id": "302a329fbabf8e92",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Start Epoch",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 2,
"halt_if": "0",
"halt_if_type": "num",
"halt_if_compare": "is_not",
"entity_id": "sensor.{HA_PRINTER_ENTITY_NAME}_print_start_epoch",
"state_type": "num",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "start_epoch",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 1570,
"y": 2000,
"wires": [
[
"94f08b2a34e68dd4"
],
[]
]
},
{
"id": "94f08b2a34e68dd4",
"type": "postgrestor",
"z": "fbda6ab16491b918",
"g": "a3e765e96362759b",
"name": "Insert Update",
"query": "UPDATE prints SET\n plate_type = '{{msg.payload}}'\nWHERE \n start_epoch = '{{msg.start_epoch}}';",
"postgresDB": "79ce3199b8eeaa1c",
"output": true,
"outputs": 1,
"x": 1480,
"y": 2040,
"wires": [
[]
]
},
{
"id": "79ce3199b8eeaa1c",
"type": "postgresDB",
"name": "3DPrint DB (PG13)",
"host": "{POSTGRES_DB_HOST}",
"hostFieldType": "str",
"port": "{POSTGRES_DB_PORT}",
"portFieldType": "num",
"database": "{POSTGRES_DB_DBNAME}",
"databaseFieldType": "str",
"ssl": "false",
"sslFieldType": "bool",
"max": "10",
"maxFieldType": "num",
"min": "1",
"minFieldType": "num",
"idle": "1000",
"idleFieldType": "num",
"connectionTimeout": "10000",
"connectionTimeoutFieldType": "num",
"user": "{POSTGRES_DB_USER}",
"userFieldType": "str",
"password": "{POSTGRES_DB_PASSWORD}",
"passwordFieldType": "str"
},
{
"id": "e2ddb329074d1a53",
"type": "group",
"z": "fbda6ab16491b918",
"name": "Filament and Plate Type Setter",
"style": {
"label": true
},
"nodes": [
"2f0c417bdc5f70ba",
"a49a2aa56216a94f",
"e91c88c6b0449efb",
"1a3a1c71ba1cf2f3",
"49e2ce35d6ced66e",
"5f11d43b46d9a943",
"5e0688f121b8fddb",
"1b174dc5a3c2cb2b",
"53d9f117e4bdc75a",
"1e3ee56ffe1d6afb",
"e72f63899b356531",
"41db1a005f0694bc",
"5be89edbbd6808a4",
"270ff91a248dd8f8",
"7a3e49eb01797119"
],
"x": 1634,
"y": 1419,
"w": 652,
"h": 382
},
{
"id": "2f0c417bdc5f70ba",
"type": "mqtt out",
"z": "fbda6ab16491b918",
"g": "e2ddb329074d1a53",
"name": "Home Assistant",
"topic": "",
"qos": "",
"retain": "",
"respTopic": "",
"contentType": "",
"userProps": "",
"correl": "",
"expiry": "",
"broker": "489094618c340eef",
"x": 2180,
"y": 1560,
"wires": []
},
{
"id": "a49a2aa56216a94f",
"type": "function",
"z": "fbda6ab16491b918",
"g": "e2ddb329074d1a53",
"name": "Printer State",
"func": "if (msg.payload == undefined) {\n return;\n}\nmsg.topic = \"homeassistant/sensor/\" + msg.machine_name + \"/\" + msg.topic + \"/state\";\n\nnode.send(msg);\n",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 2070,
"y": 1500,
"wires": [
[
"53d9f117e4bdc75a"
]
]
},
{
"id": "e91c88c6b0449efb",
"type": "function",
"z": "fbda6ab16491b918",
"g": "e2ddb329074d1a53",
"name": "Printer Config",
"func": "let data = {};\nlet payload = {};\nlet device = {};\n\nfunction getFriendlyName(str) {\n var i, word = str.split('_');\n for (i = 0; i < word.length; i++) {\n word[i] = word[i].charAt(0).toUpperCase() + word[i].slice(1);\n }\n return word.join(' ');\n}\n\nlet printer_name = msg.machine_name;\n\nlet type = \"sensor\";\nlet base_topic = \"homeassistant/\"+ type + \"/\" + msg.machine_name + \"/\" + msg.topic;\ndata.topic = base_topic + \"/config\";\npayload.name = getFriendlyName(msg.topic);\n\ndevice.identifiers = [];\ndevice.identifiers[0] = msg.machine_name;\n\ndevice.manufacturer = \"Bambu Labs\";\ndevice.model = msg.model;\ndevice.name = msg.machine_name;\nif( msg.icon != undefined) {\n payload.icon = msg.icon\n}\n\npayload.device = device;\npayload.unique_id = msg.machine_name + \"_\" + msg.topic;\npayload.object_id = payload.unique_id;\n\nif (msg.device_class != undefined)\n payload.device_class = msg.device_class;\n\nif (msg.unit_of_measurement != undefined)\n payload.unit_of_measurement = msg.unit_of_measurement;\n\n\npayload.state_topic = base_topic + \"/state\";\npayload.json_attributes_topic = base_topic + \"/attr\";\n\n\ndata.payload = payload;\n\ndata.qos = 1;\ndata.retain = true;\n\nnode.send(data);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 2080,
"y": 1460,
"wires": [
[
"53d9f117e4bdc75a"
]
]
},
{
"id": "1a3a1c71ba1cf2f3",
"type": "function",
"z": "fbda6ab16491b918",
"g": "e2ddb329074d1a53",
"name": "Format Msg",
"func": "msg.topic = \"filament\";\nif(msg.payload.material == undefined) {\n msg.payload = \"\";\n}\nelse {\n msg.payload = msg.payload.material;\n}\nmsg.machine_name = msg.values.printer;\nmsg.model = \"X1C\"\nif(msg.payload == \"\") {\n msg.payload = \"None\"\n}\n\nmsg.machine_name = \"X1C_\" + msg.values.printer;\n\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 2030,
"y": 1700,
"wires": [
[
"270ff91a248dd8f8"
]
]
},
{
"id": "49e2ce35d6ced66e",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "e2ddb329074d1a53",
"name": "Printer Name",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "sensor.{HA_PRINTER_ENTITY_NAME}_machine_name",
"state_type": "str",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "values.printer",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 2010,
"y": 1660,
"wires": [
[
"1a3a1c71ba1cf2f3"
]
]
},
{
"id": "5f11d43b46d9a943",
"type": "trigger-state",
"z": "fbda6ab16491b918",
"g": "e2ddb329074d1a53",
"name": "When Print Ends or Pause",
"server": "ed9339d3bdf92870",
"version": 2,
"exposeToHomeAssistant": false,
"haConfig": [
{
"property": "name",
"value": ""
},
{
"property": "icon",
"value": ""
}
],
"entityid": "sensor.{HA_PRINTER_ENTITY_NAME}_print_status",
"entityidfiltertype": "exact",
"debugenabled": false,
"constraints": [
{
"targetType": "this_entity",
"targetValue": "",
"propertyType": "previous_state",
"propertyValue": "old_state.state",
"comparatorType": "is_not",
"comparatorValueDatatype": "str",
"comparatorValue": "OFFLINE"
},
{
"targetType": "this_entity",
"targetValue": "",
"propertyType": "current_state",
"propertyValue": "new_state.state",
"comparatorType": "is_not",
"comparatorValueDatatype": "str",
"comparatorValue": "OFFLINE"
},
{
"targetType": "this_entity",
"targetValue": "",
"propertyType": "current_state",
"propertyValue": "new_state.state",
"comparatorType": "is_not",
"comparatorValueDatatype": "str",
"comparatorValue": "RUNNING"
},
{
"targetType": "this_entity",
"targetValue": "",
"propertyType": "current_state",
"propertyValue": "new_state.state",
"comparatorType": "is_not",
"comparatorValueDatatype": "str",
"comparatorValue": "IDLE"
},
{
"targetType": "this_entity",
"targetValue": "",
"propertyType": "previous_state",
"propertyValue": "old_state.state",
"comparatorType": "is_not",
"comparatorValueDatatype": "str",
"comparatorValue": ""
},
{
"targetType": "this_entity",
"targetValue": "",
"propertyType": "previous_state",
"propertyValue": "old_state.state",
"comparatorType": "is_not",
"comparatorValueDatatype": "str",
"comparatorValue": "FINISH"
},
{
"targetType": "this_entity",
"targetValue": "",
"propertyType": "previous_state",
"propertyValue": "old_state.state",
"comparatorType": "is_not",
"comparatorValueDatatype": "str",
"comparatorValue": "FAILED"
},
{
"targetType": "this_entity",
"targetValue": "",
"propertyType": "current_state",
"propertyValue": "new_state.state",
"comparatorType": "is_not",
"comparatorValueDatatype": "str",
"comparatorValue": "PREPARE"
}
],
"inputs": 0,
"outputs": 2,
"customoutputs": [],
"outputinitially": false,
"state_type": "str",
"enableInput": false,
"x": 1770,
"y": 1460,
"wires": [
[
"1b174dc5a3c2cb2b"
],
[]
]
},
{
"id": "5e0688f121b8fddb",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "e2ddb329074d1a53",
"name": "If Failed",
"property": "payload",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "FAILED",
"vt": "str"
},
{
"t": "eq",
"v": "FINISH",
"vt": "str"
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 3,
"x": 1820,
"y": 1560,
"wires": [
[
"e72f63899b356531"
],
[
"e72f63899b356531"
],
[]
]
},
{
"id": "1b174dc5a3c2cb2b",
"type": "delay",
"z": "fbda6ab16491b918",
"g": "e2ddb329074d1a53",
"name": "",
"pauseType": "delay",
"timeout": "1",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"x": 1740,
"y": 1500,
"wires": [
[
"5e0688f121b8fddb"
]
]
},
{
"id": "53d9f117e4bdc75a",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "e2ddb329074d1a53",
"x": 2180,
"y": 1480,
"wires": [
[
"2f0c417bdc5f70ba"
]
]
},
{
"id": "1e3ee56ffe1d6afb",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "e2ddb329074d1a53",
"x": 1960,
"y": 1500,
"wires": [
[
"e91c88c6b0449efb",
"a49a2aa56216a94f"
]
]
},
{
"id": "e72f63899b356531",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "e2ddb329074d1a53",
"x": 1940,
"y": 1620,
"wires": [
[
"49e2ce35d6ced66e"
]
]
},
{
"id": "41db1a005f0694bc",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "e2ddb329074d1a53",
"x": 1900,
"y": 1720,
"wires": [
[
"49e2ce35d6ced66e"
]
]
},
{
"id": "5be89edbbd6808a4",
"type": "function",
"z": "fbda6ab16491b918",
"g": "e2ddb329074d1a53",
"name": "Format Msg",
"func": "msg.topic = \"plate_type\";\nif(msg.payload == undefined) {\n msg.payload = \"\";\n}\nelse {\n msg.payload = msg.payload;\n}\nmsg.machine_name = msg.values.printer;\nmsg.model = \"X1C\"\n\nif(msg.payload == \"\") {\n msg.payload = \"Unknown\"\n}\n\nmsg.machine_name = \"X1C_\" + msg.values.printer;\n\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 2030,
"y": 1760,
"wires": [
[
"270ff91a248dd8f8"
]
]
},
{
"id": "270ff91a248dd8f8",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "e2ddb329074d1a53",
"x": 2220,
"y": 1700,
"wires": [
[
"1e3ee56ffe1d6afb"
]
]
},
{
"id": "7a3e49eb01797119",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "e2ddb329074d1a53",
"name": "Printer Name",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "sensor.{HA_PRINTER_ENTITY_NAME}_machine_name",
"state_type": "str",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "values.printer",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 1870,
"y": 1760,
"wires": [
[
"5be89edbbd6808a4"
]
]
},
{
"id": "ed9339d3bdf92870",
"type": "server",
"name": "Home Assistant",
"version": 5,
"addon": false,
"rejectUnauthorizedCerts": true,
"ha_boolean": "y|yes|true|on|home|open",
"connectionDelay": true,
"cacheJson": true,
"heartbeat": false,
"heartbeatInterval": "30",
"areaSelector": "friendlyName",
"deviceSelector": "friendlyName",
"entitySelector": "friendlyName",
"statusSeparator": ": ",
"statusYear": "hidden",
"statusMonth": "short",
"statusDay": "numeric",
"statusHourCycle": "default",
"statusTimeFormat": "h:m",
"enableGlobalContextStore": false
}
]
[
{
"id": "bb9dffae323b6310",
"type": "group",
"z": "fbda6ab16491b918",
"name": "Print File Selector",
"style": {
"label": true
},
"nodes": [
"d944cafd5681f32b",
"03587c53b099b76c",
"728d5c9bcbc5d97e",
"2196bc51b771b671",
"2bec4f3a309b7220",
"e271d479fb091e51",
"4c028901a71386c2",
"a34d8e29aa8729fe",
"a8ad6e035dcc2b23",
"1dea909495a29f8d",
"5f42bd36240b725a",
"04a43722d69b7b32",
"2b07025e4b6d40c2",
"a5d80d8e8c7c7c51",
"ec1b76c62de8924a",
"b5ad8602cc43dea7",
"fb2de4b4ba4298d0",
"d6a8ed80650b17a0",
"000015e4b0dfbfe6",
"ac336f79b12192d2",
"1a5c25285389e8ea",
"0b77b5da884b35b7",
"5a0e7674add44437",
"0334752848227d2c",
"549c2180bbd85815",
"b0e277cec125a10b",
"30200abf2a82cb86",
"663d4c5f5ed9c210",
"5ecfe9b2dc948e5e",
"63e1d59cc9f131ca",
"a45d4fa5185d9399",
"79e01cedc907d8b1",
"4c9375ba5a2dd908",
"2338d91b8a08edcf",
"6169aa51e9351c7f",
"2622614e22fc9bd1",
"4dd4a3fec882c618",
"cc7f156ca0dd0aec",
"91e8842199f32d53",
"516746ea7a106b1b"
],
"x": 54,
"y": 2339,
"w": 1152,
"h": 682
},
{
"id": "d944cafd5681f32b",
"type": "python-function-ps",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "List 3MF Files (Py)",
"pythonPathType": "local",
"pythonPath": "python3",
"globalPythonName": "",
"importPathList": [],
"fnCode": "import ftplib\nimport ssl\nimport platform\n\nftplib.ssl_version = ssl.PROTOCOL_TLSv1_2\n\nclass ImplicitFTP_TLS(ftplib.FTP_TLS):\n \"\"\"FTP_TLS subclass that automatically wraps sockets in SSL to support implicit FTPS.\"\"\"\n\n def __init__(self, *args, **kwargs):\n super().__init__(*args, **kwargs)\n self._sock = None\n\n @property\n def sock(self):\n \"\"\"Return the socket.\"\"\"\n return self._sock\n\n @sock.setter\n def sock(self, value):\n \"\"\"When modifying the socket, ensure that it is ssl wrapped.\"\"\"\n if value is not None and not isinstance(value, ssl.SSLSocket):\n value = self.context.wrap_socket(value)\n self._sock = value\n\n def ntransfercmd(self, cmd, rest=None):\n conn, size = ftplib.FTP.ntransfercmd(self, cmd, rest)\n if self._prot_p:\n session = self.sock.session\n if isinstance(self.sock, ssl.SSLSocket):\n session = self.sock.session\n conn = self.context.wrap_socket(conn,\n server_hostname=self.host,\n session=session) # this is the fix\n return conn, size\n \nftps = ImplicitFTP_TLS()\n\nftps.connect(host=\"{PRINTER_IP}\", port=990)\n\nftps.login(user=\"bblp\", passwd=\"{ACCESS_CODE}\")\nftps.prot_p()\n\nli = ftps.nlst(\"*.3mf\")\nli2 = ftps.nlst(\"/cache\")\n\nli = li + li2\n\nli = [ x for x in li if \".3mf\" in x ]\n\nmsg[\"files\"] = li\n\nftps.close()\nreturn msg\n\n",
"x": 430,
"y": 2460,
"wires": [
[
"4c028901a71386c2"
]
]
},
{
"id": "03587c53b099b76c",
"type": "inject",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "List Filtes",
"props": [],
"repeat": "60",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"x": 170,
"y": 2460,
"wires": [
[
"91e8842199f32d53"
]
]
},
{
"id": "728d5c9bcbc5d97e",
"type": "function",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "format",
"func": "let list = {};\nmsg.count = 0;\nif (msg.files != undefined) {\n msg.count = msg.files.length\n}\n\nmsg.machine_name = msg.values.printer;\nmsg.model = \"X1C\"\nmsg.machine_name = \"X1C_\" + msg.values.printer;\n\nmsg.files.push(\"\");\nlet filemsg = {};\nfilemsg.topic = \"files\";\nfilemsg.type = \"select\";\nfilemsg.payload = msg.files;\nfilemsg.model = msg.model;\nfilemsg.machine_name = msg.machine_name;\nnode.send(filemsg);\n\nlet filecountmsg = {};\nfilecountmsg.topic = \"file_count\";\nfilecountmsg.type = \"sensor\";\nfilecountmsg.payload = msg.count;\nfilecountmsg.model = msg.model;\nfilecountmsg.machine_name = msg.machine_name;\nnode.send(filecountmsg);\n\nlet toggle = {};\ntoggle.type = \"switch\";\ntoggle.machine_name = msg.machine_name;\ntoggle.model = msg.model;\n\ntoggle.topic = \"timelapse\";\nnode.send(toggle);\n\ntoggle.topic = \"bed_leveling\";\nnode.send(toggle);\n\ntoggle.topic = \"vibration_calibration\";\nnode.send(toggle);\n\ntoggle.topic = \"flow_calibration\";\nnode.send(toggle);\n\ntoggle.topic = \"first_layer_inspection\";\nnode.send(toggle);\n\ntoggle.topic = \"use_AMS\";\nnode.send(toggle);\n\nlet input = {};\ninput.topic = \"name\";\ninput.type = \"text\";\n\ninput.machine_name = msg.machine_name;\ninput.model = msg.model;\n\nnode.send(input);\n\nlet platenum = {};\nplatenum.topic = \"plate_number\";\nplatenum.type = \"number\";\n\nplatenum.machine_name = msg.machine_name;\nplatenum.model = msg.model;\nnode.send(platenum);\n\nlet print_set = {};\nprint_set.topic=\"print_with_settings\";\nprint_set.type = \"button\";\nprint_set.machine_name = msg.machine_name;\nprint_set.model = msg.model;\nnode.send(print_set);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 350,
"y": 2500,
"wires": [
[
"2622614e22fc9bd1"
]
]
},
{
"id": "2196bc51b771b671",
"type": "function",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "Printer State",
"func": "let printer_name = msg.machine_name;\nif(msg.payload == undefined && msg.values == undefined) {\n return;\n}\nlet type = \"switch\";\nmsg.machine_name = msg.machine_name + \"_Directory\";\nif (msg.topic == \"file_count\") {\n msg.topic = \"homeassistant/sensor/\" + msg.machine_name + \"/\" + msg.topic + \"/state\";\n node.send(msg);\n}\nelse if(msg.values != undefined){\n if (msg.topic == \"plate_number\" && (msg.values.plate == undefined || isNaN(msg.values.plate))) {\n msg.payload = 1;\n msg.topic = \"homeassistant/\" + \"number\" + \"/\" + msg.machine_name + \"/\" + msg.topic + \"/set\";\n node.send(msg);\n\n // assume if this is nan, all others have not been initialized\n msg.topic = \"homeassistant/\" + \"switch\" + \"/\" + msg.machine_name + \"/\" + \"bed_leveling\" + \"/set\";\n msg.payload = 'off';\n node.send(msg);\n\n msg.topic = \"homeassistant/\" + \"switch\" + \"/\" + msg.machine_name + \"/\" + \"timelapse\" + \"/set\";\n node.send(msg);\n\n msg.topic = \"homeassistant/\" + \"switch\" + \"/\" + msg.machine_name + \"/\" + \"use_AMS\" + \"/set\";\n node.send(msg);\n\n msg.topic = \"homeassistant/\" + \"switch\" + \"/\" + msg.machine_name + \"/\" + \"vibration_calibration\" + \"/set\";\n node.send(msg);\n\n msg.topic = \"homeassistant/\" + \"switch\" + \"/\" + msg.machine_name + \"/\" + \"flow_calibration\" + \"/set\";\n node.send(msg);\n\n msg.topic = \"homeassistant/\" + \"switch\" + \"/\" + msg.machine_name + \"/\" + \"first_layer_inspection\" + \"/set\";\n node.send(msg);\n\n\n msg.topic = \"homeassistant/\" + \"text\" + \"/\" + msg.machine_name + \"/\" + \"name\" + \"/set\";\n msg.payload = \"\";\n node.send(msg);\n\n\n msg.topic = \"homeassistant/\" + \"select\" + \"/\" + msg.machine_name + \"/\" + \"files\" + \"/set\";\n msg.payload = \"\";\n node.send(msg);\n\n }\n else {\n return;\n }\n\n}",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 770,
"y": 2580,
"wires": [
[
"0b77b5da884b35b7"
]
]
},
{
"id": "2bec4f3a309b7220",
"type": "function",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "Printer Config",
"func": "let data = {};\nlet payload = {};\nlet device = {};\n\nfunction getFriendlyName(str) {\n var i, word = str.split('_');\n for (i = 0; i < word.length; i++) {\n word[i] = word[i].charAt(0).toUpperCase() + word[i].slice(1);\n }\n return word.join(' ');\n}\n\nlet type = \"sensor\";\nif (msg.type != undefined) {\n type = msg.type;\n}\n\nif (msg.topic == \"files\") {\n type = \"select\";\n}\nlet printer_name = msg.machine_name;\nmsg.machine_name = msg.machine_name + \"_Directory\";\n\nlet base_topic = \"homeassistant/\" + type + \"/\" + msg.machine_name + \"/\" + msg.topic;\ndata.topic = base_topic + \"/config\";\npayload.name = getFriendlyName(msg.topic);\n\ndevice.identifiers = [];\ndevice.identifiers[0] = msg.machine_name;\nif (msg.topic == \"serial_number\") {\n device.identifiers[1] = msg.payload;\n}\n\npayload.availability_topic = \"homeassistant/\" + \"sensor\" + \"/\" + printer_name + \"/\" + \"status\" + \"/state\";\n\ndata.retain = true;\nif (msg.topic == \"files\") {\n type = \"select\";\n payload.command_topic = \"homeassistant/\" + \"select\" + \"/\" + msg.machine_name + \"/\" + msg.topic + \"/set\";\n payload.state_topic = \"homeassistant/\" + \"select\" + \"/\" + msg.machine_name + \"/\" + msg.topic + \"/set\";\n payload.options = msg.payload;\n}\n\nelse if (msg.topic == \"file_count\") {\n payload.state_topic = base_topic + \"/state\";\n}\n\nelse if (type == \"switch\") {\n payload.command_topic = \"homeassistant/\" + type + \"/\" + msg.machine_name + \"/\" + msg.topic + \"/set\";\n payload.state_topic = \"homeassistant/\" + type + \"/\" + msg.machine_name + \"/\" + msg.topic + \"/set\";\n payload.payload_on = 'on';\n payload.payload_off = 'off';\n payload.state_on = 'on';\n payload.state_off = 'off';\n // I give up on making AMS disabled if you have none selected. MQTT Just doesn't let me set it unavailable consistently\n /*if (msg.topic == \"use_AMS\") {\n if (msg.values != undefined && msg.values.ams_count != undefined) {\n if (isNaN(msg.values.ams_count) || msg.values.ams_count <= 0) {\n payload.availability_topic = \"homeassistant/\" + \"sensor\" + \"/\" + printer_name + \"/\" + \"status\" + \"/DO_NOT_EXIST\";\n data.reset = true;\n }\n }\n else {\n payload.availability_topic = \"homeassistant/\" + \"sensor\" + \"/\" + printer_name + \"/\" + \"status\" + \"/state\";\n data.reset = true;\n }\n }*/\n /*if (msg.topic == \"use_AMS\") {\n payload.availability_topic = \"homeassistant/\" + \"sensor\" + \"/\" + printer_name + \"/\" + \"ams_count\" + \"/state\";\n payload.availability_template = '{{ 1 if (value >= 1) else 0 }}'\n payload.payload_available = 1;\n payload.payload_not_available = 0;\n }*/\n}\n\nelse if (type == \"button\") {\n payload.command_topic = \"homeassistant/\" + type + \"/\" + msg.machine_name + \"/\" + msg.topic;\n // payload.state_topic = \"homeassistant/\" + type + \"/\" + msg.machine_name + \"/\" + msg.topic + \"/state\";\n}\n\nelse {\n payload.command_topic = \"homeassistant/\" + type + \"/\" + msg.machine_name + \"/\" + msg.topic + \"/set\";\n payload.state_topic = \"homeassistant/\" + type + \"/\" + msg.machine_name + \"/\" + msg.topic + \"/set\";\n}\nif (type == \"number\") {\n payload.min = 1;\n payload.max = 100;\n payload.mode = \"box\";\n}\nif (type == \"text\") {\n}\n\ndevice.manufacturer = \"Bambu Labs\";\ndevice.model = msg.model;\ndevice.name = msg.machine_name;\ndevice.via_device = printer_name;\n\nif (msg.icon != undefined) {\n payload.icon = msg.icon\n}\n\npayload.device = device;\npayload.unique_id = msg.machine_name + \"_\" + msg.topic;\npayload.object_id = payload.unique_id;\n\nif (msg.device_class != undefined)\n payload.device_class = msg.device_class;\n\nif (msg.unit_of_measurement != undefined)\n payload.unit_of_measurement = msg.unit_of_measurement;\n\ndata.payload = payload;\n\ndata.qos = 1;\n\nnode.send(data);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 760,
"y": 2540,
"wires": [
[
"0b77b5da884b35b7"
]
]
},
{
"id": "e271d479fb091e51",
"type": "mqtt out",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "Home Assistant",
"topic": "",
"qos": "",
"retain": "",
"respTopic": "",
"contentType": "",
"userProps": "",
"correl": "",
"expiry": "",
"broker": "489094618c340eef",
"x": 1100,
"y": 2560,
"wires": []
},
{
"id": "4c028901a71386c2",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "Printer Name",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "sensor.{HA_PRINTER_ENTITY_NAME}_machine_name",
"state_type": "str",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "values.printer",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 190,
"y": 2500,
"wires": [
[
"728d5c9bcbc5d97e"
]
]
},
{
"id": "a34d8e29aa8729fe",
"type": "mqtt in",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "HomeAssistant In",
"topic": "homeassistant/button/X1C_{PRINTER_NAME}_Directory/print_with_settings",
"qos": "2",
"datatype": "auto-detect",
"broker": "489094618c340eef",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 200,
"y": 2780,
"wires": [
[
"1dea909495a29f8d"
]
]
},
{
"id": "a8ad6e035dcc2b23",
"type": "function",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "Print File",
"func": "if (msg.values.name == undefined || msg.values.name == \"\" || msg.values.name == \"unknown\" || msg.values.name == \"unavailable\") {\n msg.values.name = msg.values.file;\n msg.values.name = msg.values.name.replace(\".gcode\", \"\");\n msg.values.name = msg.values.name.replace(\".3mf\", \"\");\n msg.values.name = msg.values.name.replace(\"/cache/\", \"\");\n msg.values.name = msg.values.name.replace(\"cache/\", \"\");\n}\nif(msg.values.plate == undefined || msg.values.plate <=0) {\n msg.values.plate = 1;\n}\nif(isNaN(msg.values.ams_count) || msg.values.ams_count <= 0) {\n msg.values.ams = false;\n}\n\nlet template = {\n \"print\" : {\n \"command\": \"project_file\",\n \"param\": `Metadata/plate_${msg.values.plate}.gcode`,\n \"url\": `ftp://${msg.values.file}`,\n \"subtask_name\": msg.values.name,\n \"timelapse\": msg.values.timelapse,\n \"bed_leveling\": msg.values.bed_level,\n \"flow_cali\": msg.values.flow_cali,\n \"vibration_cali\": msg.values.vibration_cali,\n \"layer_inspect\": msg.values.inspect,\n \"use_ams\": msg.values.ams,\n \"sequence_id\": \"2106\"\n }\n}\n\nif(msg.values.file == undefined || msg.values.file == \"\") {\n return;\n}\nmsg.payload = template;\nmsg.topic = `device/${msg.values.printer_serial}/request`;\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 660,
"y": 2840,
"wires": [
[
"ac336f79b12192d2"
]
]
},
{
"id": "1dea909495a29f8d",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "Printer State",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "sensor.{HA_PRINTER_ENTITY_NAME}_print_status",
"state_type": "str",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "values.printer_status",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 370,
"y": 2780,
"wires": [
[
"000015e4b0dfbfe6"
]
]
},
{
"id": "5f42bd36240b725a",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "Enable Bed Levelling",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "switch.{HA_PRINTER_ENTITY_NAME}_directory_bed_leveling",
"state_type": "habool",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "values.bed_level",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 360,
"y": 2840,
"wires": [
[
"04a43722d69b7b32"
]
]
},
{
"id": "04a43722d69b7b32",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "Enable Timelapse",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "switch.{HA_PRINTER_ENTITY_NAME}_directory_timelapse",
"state_type": "habool",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "values.timelapse",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 230,
"y": 2900,
"wires": [
[
"2b07025e4b6d40c2"
]
]
},
{
"id": "2b07025e4b6d40c2",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "Enable Flow",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "switch.{HA_PRINTER_ENTITY_NAME}_directory_flow_calibration",
"state_type": "habool",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "values.flow_cali",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 410,
"y": 2900,
"wires": [
[
"a5d80d8e8c7c7c51"
]
]
},
{
"id": "a5d80d8e8c7c7c51",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "Enable Vibration",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "switch.{HA_PRINTER_ENTITY_NAME}_directory_vibration_calibration",
"state_type": "habool",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "values.vibration_cali",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 220,
"y": 2940,
"wires": [
[
"ec1b76c62de8924a"
]
]
},
{
"id": "ec1b76c62de8924a",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "Enable Layer Inspect",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "switch.{HA_PRINTER_ENTITY_NAME}_directory_first_layer_inspection",
"state_type": "habool",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "values.inspect",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 420,
"y": 2940,
"wires": [
[
"b5ad8602cc43dea7"
]
]
},
{
"id": "b5ad8602cc43dea7",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "Enable AMS",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "switch.{HA_PRINTER_ENTITY_NAME}_directory_use_ams",
"state_type": "habool",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "values.ams",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 210,
"y": 2980,
"wires": [
[
"fb2de4b4ba4298d0"
]
]
},
{
"id": "fb2de4b4ba4298d0",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "Print Name",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "text.{HA_PRINTER_ENTITY_NAME}_directory_name",
"state_type": "str",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "values.name",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 370,
"y": 2980,
"wires": [
[
"d6a8ed80650b17a0"
]
]
},
{
"id": "d6a8ed80650b17a0",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "Print Plate",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "number.{HA_PRINTER_ENTITY_NAME}_directory_plate_number",
"state_type": "num",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "values.plate",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 530,
"y": 2980,
"wires": [
[
"1a5c25285389e8ea"
]
]
},
{
"id": "000015e4b0dfbfe6",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "",
"property": "values.printer_status",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "RUNNING",
"vt": "str"
},
{
"t": "eq",
"v": "OFFLINE",
"vt": "str"
},
{
"t": "eq",
"v": "PAUSED",
"vt": "str"
},
{
"t": "eq",
"v": "PAUSE",
"vt": "str"
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 5,
"x": 190,
"y": 2840,
"wires": [
[],
[],
[],
[],
[
"5f42bd36240b725a"
]
]
},
{
"id": "ac336f79b12192d2",
"type": "mqtt out",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "bambu-mqtt-out {PRINTER_NAME}",
"topic": "",
"qos": "1",
"retain": "false",
"respTopic": "",
"contentType": "",
"userProps": "",
"correl": "",
"expiry": "",
"broker": "{GENERATED_PRINTER_MQTT_ID}",
"x": 730,
"y": 2780,
"wires": []
},
{
"id": "1a5c25285389e8ea",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "Print File",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "select.{HA_PRINTER_ENTITY_NAME}_directory_files",
"state_type": "str",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "values.file",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 680,
"y": 2980,
"wires": [
[
"0334752848227d2c"
]
]
},
{
"id": "0b77b5da884b35b7",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"x": 880,
"y": 2580,
"wires": [
[
"63e1d59cc9f131ca"
]
]
},
{
"id": "5a0e7674add44437",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"x": 400,
"y": 2540,
"wires": [
[
"2bec4f3a309b7220",
"30200abf2a82cb86"
]
]
},
{
"id": "0334752848227d2c",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "Printer Serial",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "sensor.{HA_PRINTER_ENTITY_NAME}_serial_number",
"state_type": "str",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "values.printer_serial",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 650,
"y": 2940,
"wires": [
[
"cc7f156ca0dd0aec"
]
]
},
{
"id": "549c2180bbd85815",
"type": "comment",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "Directory Flow: REV 46",
"info": "Rev 31: 2023-03-05\n\nINITIAL\n- Added Print File Selector, you can now start a print remotely from home assistant if the file is on your SD card and you know which plate to run\n",
"x": 200,
"y": 2380,
"wires": []
},
{
"id": "b0e277cec125a10b",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "Print Plate",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "number.{HA_PRINTER_ENTITY_NAME}_directory_plate_number",
"state_type": "num",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "values.plate",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 450,
"y": 2620,
"wires": [
[
"2196bc51b771b671"
]
]
},
{
"id": "30200abf2a82cb86",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"x": 400,
"y": 2580,
"wires": [
[
"5ecfe9b2dc948e5e",
"2196bc51b771b671"
]
]
},
{
"id": "663d4c5f5ed9c210",
"type": "delay",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "",
"pauseType": "delay",
"timeout": "5",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"x": 300,
"y": 2620,
"wires": [
[
"b0e277cec125a10b"
]
]
},
{
"id": "5ecfe9b2dc948e5e",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "",
"property": "topic",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "plate_number",
"vt": "str"
}
],
"checkall": "true",
"repair": false,
"outputs": 1,
"x": 170,
"y": 2620,
"wires": [
[
"663d4c5f5ed9c210"
]
]
},
{
"id": "63e1d59cc9f131ca",
"type": "rbe",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "",
"func": "rbe",
"gap": "",
"start": "",
"inout": "out",
"septopics": true,
"property": "payload",
"topi": "topic",
"x": 970,
"y": 2500,
"wires": [
[
"a45d4fa5185d9399"
]
]
},
{
"id": "a45d4fa5185d9399",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "",
"property": "topic",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "",
"vt": "str"
},
{
"t": "cont",
"v": "unknown",
"vt": "str"
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 3,
"x": 1090,
"y": 2500,
"wires": [
[],
[],
[
"e271d479fb091e51"
]
]
},
{
"id": "79e01cedc907d8b1",
"type": "inject",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "Reset Timer Interval",
"props": [
{
"p": "reset",
"v": "true",
"vt": "bool"
}
],
"repeat": "300",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"x": 1040,
"y": 2400,
"wires": [
[
"4c9375ba5a2dd908"
]
]
},
{
"id": "4c9375ba5a2dd908",
"type": "change",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "Reset",
"rules": [
{
"t": "set",
"p": "reset",
"pt": "msg",
"to": "true",
"tot": "bool"
},
{
"t": "set",
"p": "topic",
"pt": "msg",
"to": "",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 1090,
"y": 2440,
"wires": [
[
"63e1d59cc9f131ca"
]
]
},
{
"id": "2338d91b8a08edcf",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "Printer AMS Count",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "sensor.{HA_PRINTER_ENTITY_NAME}_ams_count",
"state_type": "num",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "values.ams_count",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 730,
"y": 2420,
"wires": [
[
"6169aa51e9351c7f"
]
]
},
{
"id": "6169aa51e9351c7f",
"type": "function",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "Force_AMS",
"func": "if(msg.topic == \"use_AMS\") {\n if(msg.values != undefined && msg.values.ams_count != undefined) {\n if(isNaN(msg.values.ams_count) || msg.values.ams_count <= 0) {\n msg.payload = 'off';\n }\n }\n}\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 710,
"y": 2460,
"wires": [
[
"4dd4a3fec882c618"
]
]
},
{
"id": "2622614e22fc9bd1",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "",
"property": "topic",
"propertyType": "msg",
"rules": [
{
"t": "cont",
"v": "AMS",
"vt": "str"
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 2,
"x": 510,
"y": 2500,
"wires": [
[
"2338d91b8a08edcf"
],
[
"4dd4a3fec882c618"
]
]
},
{
"id": "4dd4a3fec882c618",
"type": "junction",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"x": 620,
"y": 2500,
"wires": [
[
"5a0e7674add44437"
]
]
},
{
"id": "cc7f156ca0dd0aec",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "Printer AMS Count",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "sensor.{HA_PRINTER_ENTITY_NAME}_ams_count",
"state_type": "num",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "values.ams_count",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 670,
"y": 2900,
"wires": [
[
"a8ad6e035dcc2b23"
]
]
},
{
"id": "91e8842199f32d53",
"type": "api-current-state",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "Printer State",
"server": "ed9339d3bdf92870",
"version": 3,
"outputs": 1,
"halt_if": "",
"halt_if_type": "str",
"halt_if_compare": "is_not",
"entity_id": "sensor.{HA_PRINTER_ENTITY_NAME}_status",
"state_type": "str",
"blockInputOverrides": false,
"outputProperties": [
{
"property": "values.printer_status",
"propertyType": "msg",
"value": "",
"valueType": "entityState"
}
],
"for": "0",
"forType": "num",
"forUnits": "minutes",
"override_topic": false,
"state_location": "payload",
"override_payload": "msg",
"entity_location": "data",
"override_data": "msg",
"x": 190,
"y": 2420,
"wires": [
[
"516746ea7a106b1b"
]
]
},
{
"id": "516746ea7a106b1b",
"type": "switch",
"z": "fbda6ab16491b918",
"g": "bb9dffae323b6310",
"name": "",
"property": "values.printer_status",
"propertyType": "msg",
"rules": [
{
"t": "eq",
"v": "online",
"vt": "str"
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 2,
"x": 330,
"y": 2420,
"wires": [
[
"d944cafd5681f32b"
],
[]
]
}
]
[
{
"id": "a8bb36f4c96539fb",
"type": "tab",
"label": "Bambu Labs Login",
"disabled": false,
"info": "",
"env": []
},
{
"id": "513f7a6c71b056d2",
"type": "http request",
"z": "a8bb36f4c96539fb",
"name": "sign in",
"method": "POST",
"ret": "txt",
"paytoqs": "ignore",
"url": "https://api.bambulab.com/v1/user-service/user/login",
"tls": "",
"persist": false,
"proxy": "",
"insecureHTTPParser": false,
"authType": "",
"senderr": false,
"headers": [],
"x": 610,
"y": 80,
"wires": [
[
"2926dee3ddcfdc55"
]
]
},
{
"id": "e2d0cff94bf02e27",
"type": "function",
"z": "a8bb36f4c96539fb",
"name": "Build header and payload",
"func": "msg.headers = {\n 'Content-Type' : 'application/json'\n};\n\n\nmsg.payload = {\n \"account\": flow.get(\"BAMBU_EMAIL\"),\n \"password\": flow.get(\"BAMBU_PASSWORD\")\n};\n\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 430,
"y": 80,
"wires": [
[
"513f7a6c71b056d2"
]
]
},
{
"id": "2926dee3ddcfdc55",
"type": "json",
"z": "a8bb36f4c96539fb",
"name": "",
"property": "payload",
"action": "obj",
"pretty": false,
"x": 390,
"y": 120,
"wires": [
[
"3470ef99be2e6022",
"d85c73e5dbb9cf5b"
]
]
},
{
"id": "5f3335d6cd76a63f",
"type": "inject",
"z": "a8bb36f4c96539fb",
"name": "Init",
"props": [
{
"p": "payload"
}
],
"repeat": "86400",
"crontab": "",
"once": true,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"x": 100,
"y": 100,
"wires": [
[
"955f493ad09c081d"
]
]
},
{
"id": "955f493ad09c081d",
"type": "change",
"z": "a8bb36f4c96539fb",
"name": "Bambu Account Config",
"rules": [
{
"t": "set",
"p": "BAMBU_EMAIL",
"pt": "flow",
"to": "{BAMBU_ACCOUNT_EMAIL}",
"tot": "str"
},
{
"t": "set",
"p": "BAMBU_PASSWORD",
"pt": "flow",
"to": "{BAMBU_ACCOUNT_PASSWORD}",
"tot": "str"
},
{
"t": "set",
"p": "BAMBU_REGION",
"pt": "global",
"to": "us.mqtt.bambulab.com",
"tot": "str"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 140,
"y": 140,
"wires": [
[
"e2d0cff94bf02e27"
]
]
},
{
"id": "7a0cfe215e0a7604",
"type": "comment",
"z": "a8bb36f4c96539fb",
"name": "NOTES",
"info": "Change the following in *Bambu Account Config*\n\nBAMBU_EMAIL: Your bambu account email\nBAMBU_PASSWORD: Your bambu account password\nBAMBU_REGION: \n If in China, use: cn.mqtt.bambulab.com\n Anywhere else, use: us.mqtt.bambulab.com\n\nIf you signed up with a third party such as google, do the following:\n\n1) Go to bambulab website and log out if you are signed in\n2) In sign in page, click on Forgot (Forgot password)\n3) Complete the reset password flow\n\nYou now will have a password for your bambu account \nusing the same email from the third party.\n\nBonus: The third party login STILL WORKS!\n\n",
"x": 90,
"y": 60,
"wires": []
},
{
"id": "3470ef99be2e6022",
"type": "function",
"z": "a8bb36f4c96539fb",
"name": "Set Access Token Global",
"func": "global.set(\"BAMBU_ACCESS_TOKEN\", msg.payload.accessToken);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 570,
"y": 120,
"wires": [
[]
]
},
{
"id": "b42f23c0c54390bc",
"type": "inject",
"z": "a8bb36f4c96539fb",
"name": "Trigger Token Delete",
"props": [],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"x": 150,
"y": 220,
"wires": [
[
"ca527d3979a0003e"
]
]
},
{
"id": "ca527d3979a0003e",
"type": "function",
"z": "a8bb36f4c96539fb",
"name": "Delete Access Token",
"func": "global.set(\"BAMBU_ACCESS_TOKEN\", null);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 400,
"y": 220,
"wires": [
[]
]
},
{
"id": "d85c73e5dbb9cf5b",
"type": "function",
"z": "a8bb36f4c96539fb",
"name": "Get jwt half",
"func": "msg.payload.jwthalf = msg.payload.accessToken.split(\".\")[1]\n\nlet pad = \"=\".repeat(((4 - (msg.payload.jwthalf).length % 4) % 4));\nmsg.payload.jwthalf = msg.payload.jwthalf + pad;\n\nvar payload = Buffer.from(msg.payload.jwthalf, 'base64')\nmsg = {\n \"payload\": payload.toString()\n}\nnode.send(msg);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 530,
"y": 160,
"wires": [
[
"a6fdcf9dea19d6e8"
]
]
},
{
"id": "a6fdcf9dea19d6e8",
"type": "json",
"z": "a8bb36f4c96539fb",
"name": "",
"property": "payload",
"action": "obj",
"pretty": false,
"x": 670,
"y": 160,
"wires": [
[
"74b588f633523219"
]
]
},
{
"id": "74b588f633523219",
"type": "function",
"z": "a8bb36f4c96539fb",
"name": "Set Bambu MQTT Username Global",
"func": "global.set(\"BAMBU_MQTT_USER\", msg.payload.username);",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 710,
"y": 200,
"wires": [
[]
]
}
]
@WolfwithSword
Copy link
Author

@totalitarian They should technically be optional already, they are only used in the postgres flow so if you don't use the DB, you can just fill in junk for them then delete the postgres box. If you do use the DB for tracking prints but don't want the metering and electric cost values, that is trickier.

It would be easier to just create dummy sensors in homeassistant with a value of 0.0 for both that remain unchanging, rather than modifying the flow for it. Would need to modify the db table definition to drop the columns, remove the nodes that fetch em and remove them from the insert/update sql nodes, etc. Then for the Grafana dashboard would need a separate version that doesn't contain calculations for those columns.

@totalitarian
Copy link

Thanks i'll just stick dummy values in for now and delete the PG DB

@WolfwithSword
Copy link
Author

Rev 39: Main and advanced flow (minor changes)

  • Added support for fetching the plate type from a printjob (hot_plate, cool_plate, etc). (Adv flow, as a sensor on printer and in postgres db)
  • Added renaming of new sensors from latest x1c firmware update (New yaml dashboard too for External Spool !!! )

@WolfwithSword
Copy link
Author

Rev 40/41: Main flow only

  • Added a new button on the printer to "Clear" / "Reset" the external spool.
  • Rev 41 is just rev 40, forgot to update the version :)

@WolfwithSword
Copy link
Author

WolfwithSword commented Apr 27, 2023

Rev 42/43: Busy day today, Main flow only

  • Added fetching the PA value calculated from doing the Lidar calibration! (Finally found out which mc_print message it is from). It will only set when the message comes in first then stay until overridden/updated.
    image

@WolfwithSword
Copy link
Author

Rev 45: Main flow only

  • Added filament unload button action which runs the built in unload gcode. If using external spool it will require manual intervention of course. Also don't run mid-print or such, just cause yknow ;)

@WolfwithSword
Copy link
Author

WolfwithSword commented May 1, 2023

Rev 46/47: Important -> ALL FLOWS (Main, Advanced Companion AND file select remote print)

  • Changed how the MQTT servers are setup. Now the guide requires you to enter in the user/password for HA MQTT and the access code of the printer.
  • The ID of the printer's mqtt is dynamically generated now based off your printer's unique name
  • The HomeAssistant MQTT is still going to be shared

This is done such that updating will be much easier after you delete the outdated flow and having multiple flows for multiple printers will be much easier to setup (just when importing, do it in a new flow and click "import copy")

This is only a BREAKING CHANGE if you had old main flows and have not yet done the other two but plan to, then you will need to update. Or if you update the any of the flows in the future, and possibly if you add more printers.

@WolfwithSword
Copy link
Author

Rev 48: Main flow and Bambu Login flow only (NOT IMPORTANT)

  • Only if you are on OLD P1P firmware and choose to connect to cloud mqtt instead of local mqtt, fixed it so now it will parse your username from the jwt token

@WolfwithSword
Copy link
Author

Rev 49: New flow - bed mesh parser!
See https://wolfwithsword.com for the guide!

@lludlow
Copy link

lludlow commented May 11, 2023

I got the basics up and running and everything except the camera (print preview). Looks like that entity never gets created

@WolfwithSword
Copy link
Author

@madbuda Did you only follow the basic implementation guide or also the advanced one with ftps? In the basic I create a placeholder for the print preview, but it only gets filled with the generated 3d model image if you use the FTPS advanced flow. Also note, it isn't going to be the printer's camera*

@lludlow
Copy link

lludlow commented May 11, 2023

@madbuda Did you only follow the basic implementation guide or also the advanced one with ftps? In the basic I create a placeholder for the print preview, but it only gets filled with the generated 3d model image if you use the FTPS advanced flow. Also note, it isn't going to be the printer's camera*

Only basic, I am working on the advanced now. That is helpful.

Have you thought about putting this all into an actual repo?

@WolfwithSword
Copy link
Author

I've considered putting it into a repo, the only benefit is having a place for reportable issues.

I think I might move it all to there on the next update - planning to update the main and advanced flows within a few weeks in preparation for another whole other flow for compatibility. The caveat being, the preferred method of installation and fetching of media images and such will be via the guides, which will be pulling directly from the repo.

@mkosmo
Copy link

mkosmo commented May 17, 2023

Any thought putting the wizards and such in a pages site run out of the repo? As much as you deserve to run some traffic to your website, I'm worried that one day you'll lose interest and they'll disappear. At least if the repo is abandoned, it's not like we have to worry about domain registration and hosting bills that you shed.

@lludlow
Copy link

lludlow commented May 17, 2023

Any thought putting the wizards and such in a pages site run out of the repo? As much as you deserve to run some traffic to your website, I'm worried that one day you'll lose interest and they'll disappear. At least if the repo is abandoned, it's not like we have to worry about domain registration and hosting bills that you shed.

This is an excellent reason to use a repo.

@WolfwithSword
Copy link
Author

Appreciate the concern, but the domain itself is surprisingly cheap (and I use it for far far more than just the site), and hosting cost is virtually non-existant for me, likely won't change.

On the next major update I will likely clone everything to a repo. I'll also make github page in it specifically for the repo to run the config wizards (it's just some basic JS). If it isn't done at the same time as the next update, it'll be shortly after. I've already started the repo private at the moment 🙂

@mkosmo
Copy link

mkosmo commented May 17, 2023

Glad to hear it. I'll miss seeing this gist being forked from mine, though lol (not that what you've done with it looks anything like the original anymore 😄)

@andrzej-woof
Copy link

Hey, I'm trying to set it up having printer in different LAN than MQTT/HomeAssistant with some port forwarding. Not sure if possible but the solution with ping -c doesn't really work for me as the external IP points to the router and it will always be on (and I have ping blocked). Since I'm new to node-red, not sure if it's possible to use some promise based functions to check particular ports being opened like here or a different shell command?

@WolfwithSword
Copy link
Author

You should be able to modify it with any other shell command if you have one that works for your setup. Previously I had used the status of the mqtt connection node to then set the connected variable but that was inconsistent, especially for p1p users, hence why I changed to a ping based method.

If that doesn't work, and if your printer will always be on the network, you can edit that shell command node and change the ping to be localhost instead, just to trick the flow to let everything work. That would be the least intrusive fix, depending on the use case.

@snoopy6489
Copy link

Hello I keep getting a error saying workspace contains some unknown node types junction. Thanks
image

@WolfwithSword
Copy link
Author

Hello I keep getting a error saying workspace contains some unknown node types junction. Thanks image

What version of nodered are you running? The junction nodes were added in v3.0.0 of july 2022. The only thing I can think of is you're running a very old version of nodered, in order to not have the "junction" node.

@snoopy6489
Copy link

Hello I keep getting a error saying workspace contains some unknown node types junction. Thanks image

What version of nodered are you running? The junction nodes were added in v3.0.0 of july 2022. The only thing I can think of is you're running a very old version of nodered, in order to not have the "junction" node.

You are right its an old version. I didn't think to check that. Sorry about that. I'm running it on casa os and the node red they have in the app store is super outdated its version 2.2.2. Thanks

@WolfwithSword
Copy link
Author

I haven't had time to redo the configurators on the github pages site yet, but it is a plan. However, since bambu released new X1C firmware with new features, I have decided to upload new flow updates to this repository instead, so it is easier to track and lets me do the configurator later, and issues can be made instead of comments if needed. Later, I will likely also add a "feature list" to it so people can know what my flows actually offer now. https://github.com/WolfwithSword/Bambu-HomeAssistant-Flows

But all flows on the website have been updated now. configurators will pull the latest from the repository. For a brief summary of additions, as well as a link to the new guide I made to add the X1C camera into home assistant, check this post: https://community.home-assistant.io/t/bambu-lab-x1-x1c-mqtt/489510/652?u=wolfwithsword

@Desterly
Copy link

Desterly commented Aug 18, 2023

@WolfwithSword:

Having an odd issue with the advanced flow since the 2.x line.

For some reason, the msg is getting dropped when passed into the python function which fetches the file from FTP. Here is the error message from nodered:

18 Aug 18:41:09 - [error] [python-function-ps:List 3MF Files (Py)] Traceback (most recent call last):
  File "/data/node_modules/node-red-contrib-python-function-ps/lib/.scripts/List 3MF Files (Py).py", line 114, in <module>
    result = python_function(req)
             ^^^^^^^^^^^^^^^^^^^^
  File "/data/node_modules/node-red-contrib-python-function-ps/lib/.scripts/List 3MF Files (Py).py", line 81, in python_function
    ftps.connect(host=msg["printer_ip"], port=990)
                      ~~~^^^^^^^^^^^^^^
KeyError: 'printer_ip'

I added a debug to the flow from "Values" and added a node.warn to the actual python script.
the debug dump shows the msg:

object
_msgid: "5b9e0e0f0ad37295"
filename: ""
printer_ip: "PRINTER"
access_code: "ACCESS"
model: "X1C"

But the message from List 3MF Files is empty:

object
_msgid: "5b9e0e0f0ad37295"

It's the same msgid but all the other values are missing.

Any thoughts?

this is nodered 3.0.2 running in a docker container
flows were updated to 2.0.2 today

@Desterly
Copy link

Figures.. as soon as I post something I figure it out. After restarting nodered it showed a palette update for node-red-contrib-python-function-ps which resolved the issue

@WolfwithSword
Copy link
Author

Figures.. as soon as I post something I figure it out. After restarting nodered it showed a palette update for node-red-contrib-python-function-ps which resolved the issue

Glad that helped! Though surprisingly that error I would not expect from the palette being out of date lol, glad it's fixed because that would be hard to debug!

@Desterly
Copy link

Figures.. as soon as I post something I figure it out. After restarting nodered it showed a palette update for node-red-contrib-python-function-ps which resolved the issue

Glad that helped! Though surprisingly that error I would not expect from the palette being out of date lol, glad it's fixed because that would be hard to debug!

Yeah me too.. I'd been banging my head against the wall for a few hours trying to track it down as it just seemed plain odd it was seeing the message id but nothing else.

@wuast94
Copy link

wuast94 commented Oct 19, 2023

I dont get the FTP part working. No matter what FTP server settings i set i get a Timeout everytime. I can connect with filezilla, so that part is working.

image

Did i miss anything?

@WolfwithSword
Copy link
Author

I dont get the FTP part working. No matter what FTP server settings i set i get a Timeout everytime. I can connect with filezilla, so that part is working.

(Just an FYI if you're using my flows, they are now being updated in a separate repo as per: https://gist.github.com/WolfwithSword/e3e4dc4f00629cc047b7cefd70d7b350?permalink_comment_id=4652936#gistcomment-4652936 )

But for the FTP if trying on your own, what you're missing is that it is FTPS over Implicit TLS. Filezilla can do Implicit TLS but not many other FTP clients can. In fact the common FTP palettes in nodered can't either - I get around it by using python with a custom wrapper I made that lets it support Implicit TLS.

@wuast94
Copy link

wuast94 commented Oct 19, 2023

A OK, i had this in mind but dont dig deeper in IT, now i know thanks 😊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment