[{
        "id": "868e4cd7.9fc578",
        "type": "tab",
        "label": "Car Dashboards",
        "disabled": false,
        "info": ""
    }, {
        "id": "88633c3e.1b273",
        "type": "tab",
        "label": "Notifications",
        "disabled": false,
        "info": ""
    }, {
        "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": "pmb_tesla_bot",
        "usernames": "",
        "chatids": "",
        "baseapiurl": "",
        "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",
        "broker": "mosquitto",
        "port": "1883",
        "clientid": "",
        "usetls": false,
        "protocolVersion": "4",
        "keepalive": "60",
        "cleansession": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthPayload": "",
        "birthMsg": {},
        "closeTopic": "",
        "closeQos": "0",
        "closePayload": "",
        "closeMsg": {},
        "willTopic": "",
        "willQos": "0",
        "willPayload": "",
        "willMsg": {},
        "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": "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"],
        "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",
        "broker": "acbce132.6eef4",
        "nl": false,
        "rap": false,
        "x": 120,
        "y": 140,
        "wires": [["892aaba0.903858"]]
    }, {
        "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,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 310,
        "y": 140,
        "wires": [["22bcecd8.fac734", "8491f8d1.1365f8"]]
    }, {
        "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": "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: '1596966476',\n    type: 'message',    \n    content: msg.payload\n}\nmsg.payload.options = {parse_mode : \"MarkdownV2\"};\nreturn msg;",
        "outputs": 1,
        "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: '1596966476',\n    type: 'message',\n    content: msg.topic\n}\nmsg.payload.options = {parse_mode : \"MarkdownV2\"};\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 550,
        "y": 80,
        "wires": [["eb20a524.af3ba"]]
    }, {
        "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": "dea66ad4.245ca",
        "type": "e-mail",
        "z": "88633c3e.1b273",
        "server": "mail.bloggs.com",
        "port": "465",
        "secure": true,
        "tls": true,
        "name": "joe@bloggs.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": 630,
        "y": 980,
        "wires": [[]]
    }, {
        "id": "eb20a524.af3ba",
        "type": "telegram sender",
        "z": "88633c3e.1b273",
        "name": "Status messages",
        "bot": "ed12f72a.03fad",
        "haserroroutput": false,
        "outputs": 1,
        "x": 750,
        "y": 80,
        "wires": [[]]
    }
]
