[ { "id": "868e4cd7.9fc578", "type": "tab", "label": "Car Dashboards", "disabled": false, "info": "" }, { "id": "88633c3e.1b273", "type": "tab", "label": "Notifications", "disabled": false, "info": "" }, { "id": "35ae2530c60e1b03", "type": "tab", "label": "Data", "disabled": false, "info": "", "env": [] }, { "id": "828acdf03ca58b4b", "type": "tab", "label": "Borgmatic", "disabled": false, "info": "", "env": [] }, { "id": "f017ed81.199d2", "type": "ui_tab", "name": "Tesla", "icon": "dashboard", "order": 1, "disabled": false, "hidden": false }, { "id": "2cca3d1a.be10ba", "type": "ui_group", "name": "Charge Status", "tab": "f017ed81.199d2", "order": 2, "disp": true, "width": "6", "collapse": false }, { "id": "51eafba7.ffc054", "type": "ui_group", "name": "Car Status", "tab": "f017ed81.199d2", "order": 1, "disp": true, "width": "8", "collapse": false }, { "id": "ed12f72a.03fad", "type": "telegram bot", "botname": "lrclfshtmcdfygldbwxvdlbot", "usernames": "", "chatids": "", "baseapiurl": "", "testenvironment": false, "updatemode": "polling", "pollinterval": "300", "usesocks": false, "sockshost": "", "socksport": "6667", "socksusername": "anonymous", "sockspassword": "", "bothost": "", "botpath": "", "localbotport": "8443", "publicbotport": "8443", "privatekey": "", "certificate": "", "useselfsignedcertificate": false, "sslterminated": false, "verboselogging": false, "info": "159696647614" }, { "id": "acbce132.6eef4", "type": "mqtt-broker", "name": "mosquitto [teslamate]", "broker": "mosquitto", "port": "1883", "clientid": "", "autoConnect": true, "usetls": false, "protocolVersion": "5", "keepalive": "60", "cleansession": true, "autoUnsubscribe": true, "birthTopic": "", "birthQos": "2", "birthPayload": "", "birthMsg": {}, "closeTopic": "", "closeQos": "0", "closePayload": "", "closeMsg": {}, "willTopic": "", "willQos": "0", "willPayload": "", "willMsg": {}, "userProps": "", "sessionExpiry": "" }, { "id": "405404f2.d8a094", "type": "ui_base", "theme": { "name": "theme-light", "lightTheme": { "default": "#0094CE", "baseColor": "#0094CE", "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", "edited": true, "reset": false }, "darkTheme": { "default": "#097479", "baseColor": "#097479", "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", "edited": false }, "customTheme": { "name": "Untitled Theme 1", "default": "#4B7930", "baseColor": "#4B7930", "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif" }, "themeState": { "base-color": { "default": "#0094CE", "value": "#0094CE", "edited": false }, "page-titlebar-backgroundColor": { "value": "#0094CE", "edited": false }, "page-backgroundColor": { "value": "#fafafa", "edited": false }, "page-sidebar-backgroundColor": { "value": "#ffffff", "edited": false }, "group-textColor": { "value": "#1bbfff", "edited": false }, "group-borderColor": { "value": "#ffffff", "edited": false }, "group-backgroundColor": { "value": "#ffffff", "edited": false }, "widget-textColor": { "value": "#111111", "edited": false }, "widget-backgroundColor": { "value": "#0094ce", "edited": false }, "widget-borderColor": { "value": "#ffffff", "edited": false }, "base-font": { "value": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif" } }, "angularTheme": { "primary": "indigo", "accents": "blue", "warn": "red", "background": "grey", "palette": "light" } }, "site": { "name": "Node-RED Dashboard", "hideToolbar": "false", "allowSwipe": "false", "lockMenu": "false", "allowTempTheme": "true", "dateFormat": "DD/MM/YYYY", "sizes": { "sx": 48, "sy": 48, "gx": 6, "gy": 6, "cx": 6, "cy": 6, "px": 0, "py": 0 } } }, { "id": "06c0b68418098ff9", "type": "mqtt-broker", "name": "mosquitto [borgmatic]", "broker": "mosquitto", "port": 1883, "clientid": "", "autoConnect": true, "usetls": false, "protocolVersion": 4, "keepalive": 60, "cleansession": true, "autoUnsubscribe": true, "birthTopic": "", "birthQos": "0", "birthRetain": "false", "birthPayload": "", "birthMsg": {}, "closeTopic": "", "closeQos": "0", "closeRetain": "false", "closePayload": "", "closeMsg": {}, "willTopic": "", "willQos": "0", "willRetain": "false", "willPayload": "", "willMsg": {}, "userProps": "", "sessionExpiry": "" }, { "id": "94fe8f4d.0557d", "type": "function", "z": "868e4cd7.9fc578", "name": "make time remaining string", "func": "var t = global.get('state');\nvar remaining = msg.payload.split('.');\nvar minutes = Math.ceil(60 * Number(\".\" + remaining[1]));\nif(t[0] != 'charging'){\n msg.payload = \"Not charging\";\n} else if(remaining[0] > 0){\n msg.payload = `${remaining[0]} hours ${minutes} minutes`\n} else {\n msg.payload = `${minutes} minutes`\n}\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "x": 740, "y": 220, "wires": [ [ "efe44f3.124a93" ] ] }, { "id": "d09c3311.862ff", "type": "function", "z": "868e4cd7.9fc578", "name": "get time", "func": "var d = new Date();\nmsg.payload = d;\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "x": 180, "y": 380, "wires": [ [ "7b0d22a9.903e24" ] ] }, { "id": "2e575816.e13368", "type": "link in", "z": "868e4cd7.9fc578", "name": "update-time", "links": [ "8491f8d1.1365f8" ], "x": 85, "y": 381, "wires": [ [ "d09c3311.862ff" ] ] }, { "id": "8491f8d1.1365f8", "type": "link out", "z": "868e4cd7.9fc578", "name": "topic-stored", "links": [ "2e575816.e13368", "cb1580bf.27615", "0c351a6c8e96e3c2" ], "x": 395, "y": 240, "wires": [] }, { "id": "22bcecd8.fac734", "type": "switch", "z": "868e4cd7.9fc578", "name": "", "property": "topic", "propertyType": "msg", "rules": [ { "t": "eq", "v": "charge_limit_soc", "vt": "str" }, { "t": "eq", "v": "usable_battery_level", "vt": "str" }, { "t": "cont", "v": "battery_range_km", "vt": "str" }, { "t": "eq", "v": "time_to_full_charge", "vt": "str" }, { "t": "else" }, { "t": "regex", "v": "charger_*", "vt": "str", "case": false } ], "checkall": "true", "repair": false, "outputs": 6, "x": 490, "y": 140, "wires": [ [ "dda683ce.b5166" ], [ "3db79d48.c4c322" ], [ "cc9cc37a.5f4a78" ], [ "94fe8f4d.0557d", "4e84bee.72facc" ], [ "5599954f.8ecf84" ], [ "cc9cc37a.5f4a78" ] ] }, { "id": "4123d5c1.d02dcc", "type": "mqtt in", "z": "868e4cd7.9fc578", "name": "", "topic": "teslamate/cars/1/#", "qos": "2", "datatype": "auto-detect", "broker": "acbce132.6eef4", "nl": false, "rap": false, "inputs": 0, "x": 120, "y": 140, "wires": [ [ "892aaba0.903858", "d282a891141c5143" ] ] }, { "id": "892aaba0.903858", "type": "function", "z": "868e4cd7.9fc578", "name": "store topic", "func": "var short_topic = msg.topic.substring(17);\n\n// create object to be used by Grafana data source\nvar tmp = [];\ntmp.push(msg.payload);\ntmp.push(parseInt(new Date().getTime()));\nglobal.set(short_topic,tmp);\nmsg.topic = short_topic;\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 310, "y": 140, "wires": [ [ "22bcecd8.fac734", "8491f8d1.1365f8", "d282a891141c5143" ] ] }, { "id": "ce57ad0f.660c1", "type": "switch", "z": "868e4cd7.9fc578", "name": "", "property": "topic", "propertyType": "msg", "rules": [ { "t": "regex", "v": "est_*", "vt": "str", "case": false }, { "t": "regex", "v": "ideal_*", "vt": "str", "case": false }, { "t": "regex", "v": "charger_actual_*", "vt": "str", "case": false }, { "t": "regex", "v": "charger_power*", "vt": "str", "case": false } ], "checkall": "true", "repair": false, "outputs": 4, "x": 872, "y": 178, "wires": [ [ "ad15c026.1d1d6" ], [ "6ab267e6.5e4b78" ], [ "2ec008a.2fb84f8" ], [ "23ca2a1b.ce5fce" ] ] }, { "id": "5599954f.8ecf84", "type": "function", "z": "868e4cd7.9fc578", "name": "fill state table", "func": "var interesting = [\n 'state',\n 'odometer',\n 'locked',\n 'shift_state',\n 'is_user_present'\n ];\nvar tmp = [];\nvar keys = global.keys().sort();\nfor (var key in keys ) {\n //if(!interesting.includes(keys[key]))\n // next;\n var t = global.get(keys[key]);\n var row = {\n \"key\": keys[key],\n \"value\": t[0]\n }\n tmp.push(row);\n} \nmsg.payload = tmp;\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "x": 690, "y": 275, "wires": [ [ "366025db.df598a" ] ] }, { "id": "4e84bee.72facc", "type": "link out", "z": "868e4cd7.9fc578", "name": "Charge time remaining", "links": [ "cb1580bf.27615" ], "x": 815, "y": 360, "wires": [] }, { "id": "cc9cc37a.5f4a78", "type": "calculator", "z": "868e4cd7.9fc578", "name": "", "inputMsgField": "payload", "outputMsgField": "payload", "operation": "round", "constant": "", "round": false, "decimals": 0, "x": 700, "y": 178, "wires": [ [ "ce57ad0f.660c1" ] ] }, { "id": "7b0d22a9.903e24", "type": "simpletime", "z": "868e4cd7.9fc578", "name": "", "mydate": true, "myymd": true, "myyear": true, "mymonth": true, "mymonthn": true, "mydom": true, "mydoy": true, "myday": true, "myhourpm": true, "myhour": true, "mytime": true, "mytimes": true, "myminute": true, "myminutes": true, "mysecond": true, "mymillis": true, "myepoch": true, "myrawdate": true, "mypm": true, "x": 332, "y": 380, "wires": [ [ "37af1984.d722ae" ] ] }, { "id": "366025db.df598a", "type": "ui_table", "z": "868e4cd7.9fc578", "group": "51eafba7.ffc054", "name": "State Table", "order": 3, "width": "8", "height": "16", "columns": [ { "field": "key", "title": "Parameter", "width": "50%", "align": "left", "formatter": "plaintext", "formatterParams": { "target": "_blank" } }, { "field": "value", "title": "Value", "width": "45%", "align": "right", "formatter": "plaintext", "formatterParams": { "target": "_blank" } } ], "outputs": 0, "cts": false, "x": 890, "y": 275, "wires": [] }, { "id": "efe44f3.124a93", "type": "ui_text", "z": "868e4cd7.9fc578", "group": "2cca3d1a.be10ba", "order": 1, "width": 0, "height": 0, "name": "Time to Full Charge", "label": "Time to Full Charge", "format": "{{msg.payload}}", "layout": "row-spread", "x": 1110, "y": 260, "wires": [] }, { "id": "ad15c026.1d1d6", "type": "ui_text", "z": "868e4cd7.9fc578", "group": "2cca3d1a.be10ba", "order": 7, "width": 0, "height": 0, "name": "", "label": "Estimated battery range", "format": "{{msg.payload}}", "layout": "row-spread", "x": 1070, "y": 100, "wires": [] }, { "id": "6ab267e6.5e4b78", "type": "ui_text", "z": "868e4cd7.9fc578", "group": "2cca3d1a.be10ba", "order": 6, "width": 0, "height": 0, "name": "", "label": "Ideal battery range", "format": "{{msg.payload}}", "layout": "row-spread", "x": 1050, "y": 140, "wires": [] }, { "id": "37af1984.d722ae", "type": "ui_text", "z": "868e4cd7.9fc578", "group": "51eafba7.ffc054", "order": 1, "width": 0, "height": 0, "name": "", "label": "Last update time", "format": "{{msg.mydate}}, {{msg.mytime}}", "layout": "row-spread", "x": 500, "y": 379, "wires": [] }, { "id": "2ec008a.2fb84f8", "type": "ui_text", "z": "868e4cd7.9fc578", "group": "2cca3d1a.be10ba", "order": 4, "width": 0, "height": 0, "name": "charger_actual_current", "label": "Charging current", "format": "{{msg.payload}} amps", "layout": "row-spread", "x": 1070, "y": 180, "wires": [] }, { "id": "23ca2a1b.ce5fce", "type": "ui_text", "z": "868e4cd7.9fc578", "group": "2cca3d1a.be10ba", "order": 5, "width": 0, "height": 0, "name": "charger_power", "label": "Charging power", "format": "{{msg.payload}} kw", "layout": "row-spread", "x": 1050, "y": 220, "wires": [] }, { "id": "3db79d48.c4c322", "type": "ui_gauge", "z": "868e4cd7.9fc578", "name": "Battery Level", "group": "2cca3d1a.be10ba", "order": 3, "width": "0", "height": "0", "gtype": "gage", "title": "Battery Level", "label": "%", "format": "{{value}}", "min": 0, "max": "100", "colors": [ "#ffff09", "#00ff00", "#ff8000" ], "seg1": "20", "seg2": "80", "x": 690, "y": 133, "wires": [] }, { "id": "dda683ce.b5166", "type": "ui_gauge", "z": "868e4cd7.9fc578", "name": "", "group": "2cca3d1a.be10ba", "order": 2, "width": 0, "height": 0, "gtype": "gage", "title": "Charge Limit", "label": "%", "format": "{{value}}", "min": 0, "max": "100", "colors": [ "#000000", "#000000", "#000000" ], "seg1": "", "seg2": "", "x": 691, "y": 91, "wires": [] }, { "id": "d282a891141c5143", "type": "debug", "z": "868e4cd7.9fc578", "name": "msg", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 410, "y": 300, "wires": [] }, { "id": "5bf1c557.464144", "type": "function", "z": "88633c3e.1b273", "name": "state changes", "func": "var new_state = msg.payload;\nvar previous_state = \"\";\n\nnode.warn(msg.topic + \": \" + msg.payload);\n\nswitch(msg.topic){\n\tcase 'state':\n\t\tprevious_state = flow.get('state');\n\t\tflow.set('state',new_state);\n if(new_state != 'driving' && previous_state != 'driving') \n return;\n\t\tif(previous_state != new_state)\n\t\t\tmsg.topic = `Tesla state changed from *${previous_state}* to *${new_state}*`\n\t\telse\n\t\t\treturn;\n\t\tbreak;\n/*\tcase 'shift_state':\n\t if(msg.payload === \"\") return;\n msg.topic = `Tesla changed gear to ${msg.payload}`\n\t\tbreak;\n*/\n case 'is_user_present':\n\t\tprevious_state = flow.get('is_user_present');\n\t\tnew_state = msg.payload;\n\t\tflow.set('is_user_present',new_state);\n\n\t\tif(previous_state != new_state)\n\t\t\tmsg.topic = `Tesla driver is present: *${new_state}*`\n\t\telse return;\n\t\tbreak;\n case 'time_to_full_charge':\n\t\tvar previous = flow.get('time_to_full_charge');\n if(flow.get('state') != 'charging' || \n previous.timeleft === msg.payload){\n node.warn('returned from 1 ' + flow.get('state'))\n return;\n }\n var now = Math.round(Date.now()/1000);\n\t\tvar current = { timestamp: now, timeleft: msg.payload};\n var remaining = msg.payload.split('.');\n var minutes = Math.ceil(60 * Number(\".\" + remaining[1]));\n \n // If more than 1 hour remaining, print max 1 time per 15 minutes\n if(remaining[0] > 0 && (now - previous.timestamp)/60 <= 15)\n return;\n // If less than 1 hour remaining, print max 1 time per 5 minutes\n if(remaining[0] == 0 && (now - previous.timestamp)/60 < 5)\n return;\n \n var how_long = \"\";\n if(remaining[0] > 0){\n how_long = `${remaining[0]} hours ${minutes} minutes`\n } else {\n how_long = `${minutes} minutes`\n }\n\t\tflow.set('time_to_full_charge',current);\n\t\tmsg.topic = `Time to full charge: *${how_long}*`;\n\t\tbreak;\n\tdefault:\n\t\treturn;\n}\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "// Code added here will be run once\n// whenever the node is deployed.\nflow.set('state','initial');\nflow.set('is_user_present','initial');\nflow.set('time_to_full_charge',{timestamp:0,timeleft:0});\n", "finalize": "", "libs": [], "x": 340, "y": 60, "wires": [ [ "8094b1d4.32f968" ] ] }, { "id": "cb1580bf.27615", "type": "link in", "z": "88633c3e.1b273", "name": "process state changes", "links": [ "8491f8d1.1365f8", "4e84bee.72facc" ], "x": 175, "y": 80, "wires": [ [ "5bf1c557.464144", "72d2c21.f2a2e3c" ] ] }, { "id": "72d2c21.f2a2e3c", "type": "function", "z": "88633c3e.1b273", "name": "geofence", "func": "/* show when car enters and leaves geofences */\nif(msg.topic != 'geofence') return;\n/* temporarly disable */\n//return;\n\nvar previous_fence = flow.get('geofence');\nvar new_fence = msg.payload;\nflow.set('geofence',new_fence);\nmsg.topic = '';\n\nif(previous_fence !== new_fence){\n if(previous_fence !== \"\")\n msg.topic = `Tesla left Geofence *${previous_fence}*`;\n if(new_fence !== \"\"){\n if(previous_fence !== \"\")\n msg.topic += ' and ';\n else\n msg.topic += 'Tesla ';\n msg.topic += `entered Geofence *${new_fence}*`;\n }\n} else return null;\nreturn msg;\n", "outputs": 1, "noerr": 0, "initialize": "// Code added here will be run once\n// whenever the node is deployed.\nflow.set('geofence','');", "finalize": "", "libs": [], "x": 320, "y": 100, "wires": [ [ "8094b1d4.32f968" ] ] }, { "id": "1da8704b.f78728", "type": "inject", "z": "88633c3e.1b273", "name": "", "props": [ { "p": "payload" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "Test from *Node\\-RED*", "payloadType": "str", "x": 210, "y": 980, "wires": [ [ "a9c28815.0191c" ] ] }, { "id": "a9c28815.0191c", "type": "function", "z": "88633c3e.1b273", "name": "create Bot message", "func": "msg.payload = {\n chatId: '6660554632',\n type: 'message', \n content: msg.payload,\n}\nmsg.payload.options = {parse_mode : \"MarkdownV2\"};\nmsg.from = \"test@veenboer.xyz\"\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 440, "y": 980, "wires": [ [ "df6e0dc2.ac982" ] ] }, { "id": "8094b1d4.32f968", "type": "function", "z": "88633c3e.1b273", "name": "Format message", "func": "msg.payload = {\n chatId: '6660554632',\n type: 'message',\n content: msg.topic,\n}\nmsg.payload.options = {parse_mode : \"MarkdownV2\"};\nmsg.from = \"nodered@rik.veenboer.xyz\"\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 550, "y": 80, "wires": [ [] ] }, { "id": "dea66ad4.245ca", "type": "e-mail", "z": "88633c3e.1b273", "server": "email-smtp.eu-west-1.amazonaws.com", "port": "587", "secure": false, "name": "rik.veenboer@gmail.com", "dname": "Email", "x": 710, "y": 140, "wires": [] }, { "id": "df6e0dc2.ac982", "type": "telegram sender", "z": "88633c3e.1b273", "name": "Test sender", "bot": "ed12f72a.03fad", "haserroroutput": false, "outputs": 1, "x": 770, "y": 980, "wires": [ [] ] }, { "id": "eb20a524.af3ba", "type": "telegram sender", "z": "88633c3e.1b273", "name": "Status messages", "bot": "ed12f72a.03fad", "haserroroutput": false, "outputs": 1, "x": 970, "y": 80, "wires": [ [] ] }, { "id": "7d872e85d99aee28", "type": "http request", "z": "35ae2530c60e1b03", "name": "", "method": "POST", "ret": "txt", "paytoqs": "body", "url": "http://192.168.2.200:8000/state", "tls": "", "persist": false, "proxy": "", "insecureHTTPParser": false, "authType": "", "senderr": false, "headers": [], "x": 690, "y": 140, "wires": [ [ "fb81418e6b46530e" ] ] }, { "id": "0c351a6c8e96e3c2", "type": "link in", "z": "35ae2530c60e1b03", "name": "link in 1", "links": [ "8491f8d1.1365f8" ], "x": 185, "y": 160, "wires": [ [ "24fd317ac4ec1276" ] ] }, { "id": "f36f3ed1ae28ee17", "type": "mqtt in", "z": "35ae2530c60e1b03", "name": "", "topic": "dev/cars/1/#", "qos": "2", "datatype": "auto-detect", "broker": "acbce132.6eef4", "nl": false, "rap": false, "inputs": 0, "x": 200, "y": 300, "wires": [ [ "24fd317ac4ec1276" ] ] }, { "id": "24fd317ac4ec1276", "type": "switch", "z": "35ae2530c60e1b03", "name": "", "property": "topic", "propertyType": "msg", "rules": [ { "t": "eq", "v": "state", "vt": "str" } ], "checkall": "true", "repair": false, "outputs": 1, "x": 580, "y": 300, "wires": [ [ "7d872e85d99aee28", "fb81418e6b46530e" ] ] }, { "id": "f1efdc7cb2328a70", "type": "inject", "z": "35ae2530c60e1b03", "name": "", "props": [ { "p": "topic", "vt": "str" }, { "p": "payload" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "dev/cars/1/state", "payload": "online", "payloadType": "str", "x": 220, "y": 420, "wires": [ [ "24fd317ac4ec1276" ] ] }, { "id": "13e8537dd143437c", "type": "inject", "z": "35ae2530c60e1b03", "name": "", "props": [ { "p": "topic", "vt": "str" }, { "p": "payload" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "dev/cars/1/state", "payload": "offline", "payloadType": "str", "x": 220, "y": 480, "wires": [ [ "24fd317ac4ec1276" ] ] }, { "id": "fb81418e6b46530e", "type": "debug", "z": "35ae2530c60e1b03", "name": "", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "auto", "x": 830, "y": 500, "wires": [] }, { "id": "e50d0883efd82937", "type": "mqtt in", "z": "828acdf03ca58b4b", "name": "", "topic": "borgmatic/stats/#", "qos": "2", "datatype": "auto-detect", "broker": "06c0b68418098ff9", "nl": false, "rap": true, "rh": 0, "inputs": 0, "x": 150, "y": 260, "wires": [ [ "2cc041d2f5a4a7ee" ] ] }, { "id": "2cc041d2f5a4a7ee", "type": "function", "z": "828acdf03ca58b4b", "name": "function 1", "func": "const selections = [\n // [\"name\", \"name\"],\n [\"start\", \"start\"],\n [\"end\", \"end\"],\n [\"duration\", \"duration\"],\n [\"compressed_size\", \"stats.compressed_size\"],\n [\"deduplicated_size\", \"stats.deduplicated_size\"],\n [\"nfiles\", \"stats.nfiles\"],\n [\"original_size\", \"stats.original_size\"],\n];\n\nconst getPath = (obj, path) =>\n path.split('.').reduce((o, k) => (o?.[k] !== undefined ? o[k] : undefined), obj);\n\nconst namespace = msg.topic.split('/').pop()\n\nconst messages = selections.flatMap(([name, path]) => {\n const val = getPath(msg.payload, path);\n return val === undefined\n ? []\n : [{ topic: `borgmatic/split/${namespace}/${name}`, payload: val }];\n});\n\nreturn [messages];", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 440, "y": 240, "wires": [ [ "50a0bb8c03545b5c", "13e002897ab3b6ab" ] ] }, { "id": "50a0bb8c03545b5c", "type": "debug", "z": "828acdf03ca58b4b", "name": "debug 1", "active": true, "tosidebar": true, "console": true, "tostatus": false, "complete": "payload", "targetType": "msg", "statusVal": "", "statusType": "auto", "x": 650, "y": 120, "wires": [] }, { "id": "13e002897ab3b6ab", "type": "mqtt out", "z": "828acdf03ca58b4b", "name": "", "topic": "", "qos": "", "retain": "", "respTopic": "", "contentType": "", "userProps": "", "correl": "", "expiry": "", "broker": "06c0b68418098ff9", "x": 650, "y": 240, "wires": [] }, { "id": "0a5f517589902b57", "type": "node-inspector", "z": "828acdf03ca58b4b", "inputField": "payload", "host": "0.0.0.0", "portNumber": 9229, "autoStart": true, "name": "", "x": 580, "y": 340, "wires": [] }, { "id": "f297a215e3db36f2", "type": "inject", "z": "828acdf03ca58b4b", "name": "", "props": [ { "p": "topic", "vt": "str" }, { "p": "payload" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "borgmatic/stats/xyz", "payload": "{\"command_line\":[\"/opt/homebrew/bin/borg\",\"create\",\"--patterns-from\",\"/var/folders/qh/8vg7yzzx6gj8y6tw327zbt380000gn/T/borgmatic-fbvbjxj_/borgmatic/tmpusnc8t0m\",\"--compression\",\"lz4\",\"--umask\",\"22\",\"--log-json\",\"--json\",\"/Users/rik/Downloads/repo::{now:%Y-%m-%d_%H%M%S}\"],\"duration\":0.003158,\"end\":\"2025-09-30T19:45:56.000000\",\"id\":\"467e209e97503853132b3e11ec1c8e3a21e00dd8224fa1e22d541c6d1670c094\",\"limits\":{\"max_archive_size\":0.000031518997777886815},\"name\":\"2025-09-30_194556\",\"start\":\"2025-09-30T19:45:56.000000\",\"stats\":{\"compressed_size\":1170,\"deduplicated_size\":661,\"nfiles\":2,\"original_size\":1286}}", "payloadType": "json", "x": 190, "y": 420, "wires": [ [ "2cc041d2f5a4a7ee" ] ] } ]