Skip to content

Instantly share code, notes, and snippets.

@WolfwithSword
Forked from mkosmo/bambu_mqtt.json
Last active January 24, 2024 06:04
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 = \"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bnMjIj4KICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iCiAgICB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlRXZlbnQjIgogICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICAgeG1sbnM6R0lNUD0iaHR0cDovL3d3dy5naW1wLm9yZy94bXAvIgogICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iCiAgIHhtcE1NOkRvY3VtZW50SUQ9ImdpbXA6ZG9jaWQ6Z2ltcDo4ZDUxMzAzNy0xYTUxLTQ5Y2EtYTZjMS1hYjNjOTlhNTVmODIiCiAgIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NGI5ZmE4YWYtYzY5ZC00YmM4LWE2NDctMGM2NmUxNGViODU0IgogICB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6N2U3OThjODAtODA3YS00NzUwLTlhY2UtNzU5NjE1YmExOTA4IgogICBkYzpGb3JtYXQ9ImltYWdlL3BuZyIKICAgR0lNUDpBUEk9IjIuMCIKICAgR0lNUDpQbGF0Zm9ybT0iV2luZG93cyIKICAgR0lNUDpUaW1lU3RhbXA9IjE2NzYwNTQ2MDMxNzc5NzkiCiAgIEdJTVA6VmVyc2lvbj0iMi4xMC4zMiIKICAgdGlmZjpPcmllbnRhdGlvbj0iMSIKICAgeG1wOkNyZWF0b3JUb29sPSJHSU1QIDIuMTAiCiAgIHhtcDpNZXRhZGF0YURhdGU9IjIwMjM6MDI6MTBUMTQ6NDM6MjMtMDQ6MDAiCiAgIHhtcDpNb2RpZnlEYXRlPSIyMDIzOjAyOjEwVDE0OjQzOjIzLTA0OjAwIj4KICAgPHhtcE1NOkhpc3Rvcnk+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

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