PID Controller

From the following webpage node-red-contrib-pid

Play ground for the PID Controller
Export of code
[
    {
        "id": "f6f2187d.f17ca8",
        "type": "tab",
        "label": "Controller",
        "disabled": false,
        "info": ""
    },
    {
        "id": "3fa8ce724cad2896",
        "type": "tab",
        "label": "Process",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "b4973237.46ab6",
        "type": "subflow",
        "name": "Process Simulation",
        "info": "",
        "in": [
            {
                "x": 37,
                "y": 103,
                "wires": [
                    {
                        "id": "ec719d4d.0d54f8"
                    }
                ]
            }
        ],
        "out": [
            {
                "x": 728.5,
                "y": 294,
                "wires": [
                    {
                        "id": "ae1a6e5.d4c0d9",
                        "port": 0
                    }
                ]
            }
        ]
    },
    {
        "id": "50edb8b45dc0ed34",
        "type": "subflow",
        "name": "Process Simulation (2)",
        "info": "",
        "in": [
            {
                "x": 37,
                "y": 103,
                "wires": [
                    {
                        "id": "fa59ae7027328119"
                    }
                ]
            }
        ],
        "out": [
            {
                "x": 728.5,
                "y": 294,
                "wires": [
                    {
                        "id": "f67ad1b5959fccb6",
                        "port": 0
                    }
                ]
            }
        ]
    },
    {
        "id": "80cd4062.93a5",
        "type": "ui_tab",
        "name": "Home",
        "icon": "dashboard"
    },
    {
        "id": "91cf8ad51dd73124",
        "type": "ui_group",
        "name": "Controller",
        "tab": "80cd4062.93a5",
        "order": 1,
        "disp": true,
        "width": "6",
        "collapse": false,
        "className": ""
    },
    {
        "id": "c45a83a3.d00908",
        "type": "ui_group",
        "name": "PID",
        "tab": "80cd4062.93a5",
        "order": 2,
        "disp": false,
        "width": "12",
        "collapse": false,
        "className": ""
    },
    {
        "id": "b1e172772b9ec323",
        "type": "ui_base",
        "theme": {
            "name": "theme-dark",
            "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": true,
                "reset": 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": "#097479",
                    "value": "#097479",
                    "edited": false
                },
                "page-titlebar-backgroundColor": {
                    "value": "#097479",
                    "edited": false
                },
                "page-backgroundColor": {
                    "value": "#111111",
                    "edited": false
                },
                "page-sidebar-backgroundColor": {
                    "value": "#333333",
                    "edited": false
                },
                "group-textColor": {
                    "value": "#0eb8c0",
                    "edited": false
                },
                "group-borderColor": {
                    "value": "#555555",
                    "edited": false
                },
                "group-backgroundColor": {
                    "value": "#333333",
                    "edited": false
                },
                "widget-textColor": {
                    "value": "#eeeeee",
                    "edited": false
                },
                "widget-backgroundColor": {
                    "value": "#097479",
                    "edited": false
                },
                "widget-borderColor": {
                    "value": "#333333",
                    "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": "38b0c5f8be13ea94",
        "type": "ui_group",
        "name": "Control Settings",
        "tab": "80cd4062.93a5",
        "order": 3,
        "disp": true,
        "width": "6",
        "collapse": false,
        "className": ""
    },
    {
        "id": "7fe4b5c3.32e58c",
        "type": "function",
        "z": "b4973237.46ab6",
        "name": "30 sec RC + 20",
        "func": "// Applies a simple RC low pass filter to incoming payload values\nvar tc = 30*1000;       // time constant in milliseconds\n\nvar lastValue = context.get('lastValue');\nif (typeof lastValue == \"undefined\") lastValue = msg.payload;\nvar lastTime = context.get('lastTime') || null;\nvar now = new Date();\nvar currentValue = msg.payload;\nif (lastTime === null) {\n    // first time through\n    newValue = currentValue;\n} else {\n    var dt = now - lastTime;\n    var newValue;\n    \n    if (dt > 0) {\n        var dtotc = dt / tc;\n        newValue = lastValue * (1 - dtotc) + currentValue * dtotc;\n    } else {\n        // no time has elapsed leave output the same as last time\n        newValue = lastValue;\n    }\n}\ncontext.set('lastValue', newValue);\ncontext.set('lastTime', now);\n\nmsg.payload = newValue + 20;\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 626.5,
        "y": 207,
        "wires": [
            [
                "ae1a6e5.d4c0d9"
            ]
        ]
    },
    {
        "id": "1bacd004.9753c",
        "type": "inject",
        "z": "b4973237.46ab6",
        "name": "Inject -0.2 at start",
        "repeat": "",
        "crontab": "",
        "once": true,
        "topic": "",
        "payload": "-0.2",
        "payloadType": "num",
        "x": 134.5,
        "y": 30,
        "wires": [
            [
                "ec719d4d.0d54f8"
            ]
        ]
    },
    {
        "id": "999a52c2.f465f",
        "type": "function",
        "z": "b4973237.46ab6",
        "name": "10 sec RC",
        "func": "// Applies a simple RC low pass filter to incoming payload values\nvar tc = 10*1000;       // time constant in milliseconds\n\nvar lastValue = context.get('lastValue');\nif (typeof lastValue == \"undefined\") lastValue = msg.payload;\nvar lastTime = context.get('lastTime') || null;\nvar now = new Date();\nvar currentValue = msg.payload;\nif (lastTime === null) {\n    // first time through\n    newValue = currentValue;\n} else {\n    var dt = now - lastTime;\n    var newValue;\n    \n    if (dt > 0) {\n        var dtotc = dt / tc;\n        newValue = lastValue * (1 - dtotc) + currentValue * dtotc;\n    } else {\n        // no time has elapsed leave output the same as last time\n        newValue = lastValue;\n    }\n}\ncontext.set('lastValue', newValue);\ncontext.set('lastTime', now);\n\nmsg.payload = newValue;\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 451,
        "y": 207,
        "wires": [
            [
                "7fe4b5c3.32e58c"
            ]
        ]
    },
    {
        "id": "ec719d4d.0d54f8",
        "type": "delay",
        "z": "b4973237.46ab6",
        "name": "",
        "pauseType": "delay",
        "timeout": "1",
        "timeoutUnits": "seconds",
        "rate": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "outputs": 1,
        "x": 268,
        "y": 104,
        "wires": [
            [
                "ed576d5edee9bbdf"
            ]
        ]
    },
    {
        "id": "a823c9cf.2a6178",
        "type": "function",
        "z": "b4973237.46ab6",
        "name": "2 msg transport delay",
        "func": "// stores messages in a fifo until the specified number have been received, \n// then releases them as new messages are received.\n// during the filling phase the earliest message is passed on each time \n// a message is received, but it is also left in the fifo\nvar fifoMaxLength = 2;\nvar fifo = context.get('fifo') || [];\n// push the new message onto the top of the array, messages are shifted down and\n// drop off the front\nvar length = fifo.push(msg);  // returns new length\nif (length > fifoMaxLength) {\n    newMsg = fifo.shift();\n} else {\n    // not full yet, make a copy of the msg and pass it on\n    var newMsg = JSON.parse(JSON.stringify(fifo[0]));\n}\ncontext.set('fifo', fifo);\nreturn newMsg;",
        "outputs": 1,
        "noerr": 0,
        "x": 258,
        "y": 208,
        "wires": [
            [
                "999a52c2.f465f"
            ]
        ]
    },
    {
        "id": "ae1a6e5.d4c0d9",
        "type": "function",
        "z": "b4973237.46ab6",
        "name": "Clear all except payload",
        "func": "msg2 = {payload: msg.payload};\nreturn msg2;",
        "outputs": 1,
        "noerr": 0,
        "x": 545,
        "y": 293,
        "wires": [
            []
        ]
    },
    {
        "id": "ede39236.1961f8",
        "type": "range",
        "z": "b4973237.46ab6",
        "minin": "0",
        "maxin": "1",
        "minout": "0",
        "maxout": "100",
        "action": "scale",
        "round": false,
        "name": "",
        "x": 87,
        "y": 208,
        "wires": [
            [
                "a823c9cf.2a6178"
            ]
        ]
    },
    {
        "id": "ed576d5edee9bbdf",
        "type": "delay",
        "z": "b4973237.46ab6",
        "name": "",
        "pauseType": "rate",
        "timeout": "200",
        "timeoutUnits": "milliseconds",
        "rate": "1",
        "nbRateUnits": "0.2",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": true,
        "allowrate": false,
        "outputs": 1,
        "x": 470,
        "y": 100,
        "wires": [
            [
                "ede39236.1961f8"
            ]
        ]
    },
    {
        "id": "58d65d11e55bde7b",
        "type": "function",
        "z": "50edb8b45dc0ed34",
        "name": "30 sec RC + 20",
        "func": "// Applies a simple RC low pass filter to incoming payload values\nvar tc = 30*1000;       // time constant in milliseconds\n\nvar lastValue = context.get('lastValue');\nif (typeof lastValue == \"undefined\") lastValue = msg.payload;\nvar lastTime = context.get('lastTime') || null;\nvar now = new Date();\nvar currentValue = msg.payload;\nif (lastTime === null) {\n    // first time through\n    newValue = currentValue;\n} else {\n    var dt = now - lastTime;\n    var newValue;\n    \n    if (dt > 0) {\n        var dtotc = dt / tc;\n        newValue = lastValue * (1 - dtotc) + currentValue * dtotc;\n    } else {\n        // no time has elapsed leave output the same as last time\n        newValue = lastValue;\n    }\n}\ncontext.set('lastValue', newValue);\ncontext.set('lastTime', now);\n\nmsg.payload = newValue + 20;\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 626.5,
        "y": 207,
        "wires": [
            [
                "f67ad1b5959fccb6"
            ]
        ]
    },
    {
        "id": "f4d97172e6f7b3cd",
        "type": "inject",
        "z": "50edb8b45dc0ed34",
        "name": "Inject -0.2 at start",
        "repeat": "",
        "crontab": "",
        "once": true,
        "topic": "",
        "payload": "-0.2",
        "payloadType": "num",
        "x": 134.5,
        "y": 30,
        "wires": [
            [
                "fa59ae7027328119"
            ]
        ]
    },
    {
        "id": "88815681c4818fdc",
        "type": "function",
        "z": "50edb8b45dc0ed34",
        "name": "10 sec RC",
        "func": "// Applies a simple RC low pass filter to incoming payload values\nvar tc = 10*1000;       // time constant in milliseconds\n\nvar lastValue = context.get('lastValue');\nif (typeof lastValue == \"undefined\") lastValue = msg.payload;\nvar lastTime = context.get('lastTime') || null;\nvar now = new Date();\nvar currentValue = msg.payload;\nif (lastTime === null) {\n    // first time through\n    newValue = currentValue;\n} else {\n    var dt = now - lastTime;\n    var newValue;\n    \n    if (dt > 0) {\n        var dtotc = dt / tc;\n        newValue = lastValue * (1 - dtotc) + currentValue * dtotc;\n    } else {\n        // no time has elapsed leave output the same as last time\n        newValue = lastValue;\n    }\n}\ncontext.set('lastValue', newValue);\ncontext.set('lastTime', now);\n\nmsg.payload = newValue;\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 451,
        "y": 207,
        "wires": [
            [
                "58d65d11e55bde7b"
            ]
        ]
    },
    {
        "id": "fa59ae7027328119",
        "type": "delay",
        "z": "50edb8b45dc0ed34",
        "name": "",
        "pauseType": "delay",
        "timeout": "1",
        "timeoutUnits": "seconds",
        "rate": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "outputs": 1,
        "x": 268,
        "y": 104,
        "wires": [
            [
                "773fc416e53ebd90"
            ]
        ]
    },
    {
        "id": "9c160d69554e61cc",
        "type": "function",
        "z": "50edb8b45dc0ed34",
        "name": "2 msg transport delay",
        "func": "// stores messages in a fifo until the specified number have been received, \n// then releases them as new messages are received.\n// during the filling phase the earliest message is passed on each time \n// a message is received, but it is also left in the fifo\nvar fifoMaxLength = 2;\nvar fifo = context.get('fifo') || [];\n// push the new message onto the top of the array, messages are shifted down and\n// drop off the front\nvar length = fifo.push(msg);  // returns new length\nif (length > fifoMaxLength) {\n    newMsg = fifo.shift();\n} else {\n    // not full yet, make a copy of the msg and pass it on\n    var newMsg = JSON.parse(JSON.stringify(fifo[0]));\n}\ncontext.set('fifo', fifo);\nreturn newMsg;",
        "outputs": 1,
        "noerr": 0,
        "x": 258,
        "y": 208,
        "wires": [
            [
                "88815681c4818fdc"
            ]
        ]
    },
    {
        "id": "f67ad1b5959fccb6",
        "type": "function",
        "z": "50edb8b45dc0ed34",
        "name": "Clear all except payload",
        "func": "msg2 = {payload: msg.payload};\nreturn msg2;",
        "outputs": 1,
        "noerr": 0,
        "x": 545,
        "y": 293,
        "wires": [
            []
        ]
    },
    {
        "id": "773fc416e53ebd90",
        "type": "range",
        "z": "50edb8b45dc0ed34",
        "minin": "0",
        "maxin": "1",
        "minout": "0",
        "maxout": "100",
        "action": "scale",
        "round": false,
        "name": "",
        "x": 87,
        "y": 208,
        "wires": [
            [
                "9c160d69554e61cc"
            ]
        ]
    },
    {
        "id": "a7a2ed9e39340c3f",
        "type": "comment",
        "z": "f6f2187d.f17ca8",
        "name": "node-red-contrib-pid",
        "info": "",
        "x": 590,
        "y": 440,
        "wires": []
    },
    {
        "id": "e0cb2a8c.4402a8",
        "type": "PID",
        "z": "f6f2187d.f17ca8",
        "name": "",
        "setpoint": "50",
        "pb": "1000",
        "ti": "24",
        "td": "6",
        "integral_default": "0",
        "smooth_factor": "0",
        "max_interval": 600,
        "enable": "1",
        "disabled_op": "",
        "x": 550,
        "y": 340,
        "wires": [
            [
                "e94f888a.130a88",
                "4416d9ac4971e0c1",
                "97854eece794f44d",
                "5148e18ed7b309f3"
            ]
        ]
    },
    {
        "id": "f70949c8.aab988",
        "type": "change",
        "z": "f6f2187d.f17ca8",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "Output",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 870,
        "y": 320,
        "wires": [
            [
                "7e154912977853ce"
            ]
        ]
    },
    {
        "id": "de738fc5.75e4c8",
        "type": "change",
        "z": "f6f2187d.f17ca8",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "Process",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 830,
        "y": 260,
        "wires": [
            [
                "9f58a52d.076dd"
            ]
        ]
    },
    {
        "id": "e94f888a.130a88",
        "type": "range",
        "z": "f6f2187d.f17ca8",
        "minin": "0",
        "maxin": "1",
        "minout": "0",
        "maxout": "100",
        "action": "scale",
        "round": false,
        "property": "payload",
        "name": "Scale power",
        "x": 710,
        "y": 320,
        "wires": [
            [
                "f70949c8.aab988"
            ]
        ]
    },
    {
        "id": "bef0a1f8.2e2cf",
        "type": "inject",
        "z": "f6f2187d.f17ca8",
        "name": "Clear chart on deploy",
        "repeat": "",
        "crontab": "",
        "once": true,
        "topic": "",
        "payload": "{\"data\":[]}",
        "payloadType": "json",
        "x": 560,
        "y": 40,
        "wires": [
            [
                "9079ffaf.4a096"
            ]
        ]
    },
    {
        "id": "9079ffaf.4a096",
        "type": "change",
        "z": "f6f2187d.f17ca8",
        "name": "",
        "rules": [
            {
                "t": "move",
                "p": "payload.data",
                "pt": "msg",
                "to": "payload",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 796,
        "y": 40,
        "wires": [
            [
                "9f58a52d.076dd"
            ]
        ]
    },
    {
        "id": "9f58a52d.076dd",
        "type": "ui_chart",
        "z": "f6f2187d.f17ca8",
        "name": "",
        "group": "c45a83a3.d00908",
        "order": 0,
        "width": "12",
        "height": "6",
        "label": "chart",
        "chartType": "line",
        "legend": "true",
        "xformat": "HH:mm:ss",
        "interpolate": "linear",
        "nodata": "",
        "dot": false,
        "ymin": "0",
        "ymax": "100",
        "removeOlder": "3",
        "removeOlderPoints": "",
        "removeOlderUnit": "60",
        "cutout": 0,
        "useOneColor": false,
        "useUTC": false,
        "colors": [
            "#1f77b4",
            "#cf0005",
            "#ff7f0e",
            "#2ca02c",
            "#98df8a",
            "#d62728",
            "#ff9896",
            "#9467bd",
            "#c5b0d5"
        ],
        "outputs": 1,
        "useDifferentColor": false,
        "className": "",
        "x": 1190,
        "y": 140,
        "wires": [
            []
        ]
    },
    {
        "id": "0152cd5b06892d7b",
        "type": "comment",
        "z": "f6f2187d.f17ca8",
        "name": "node-red-dashboard",
        "info": "",
        "x": 1070,
        "y": 200,
        "wires": []
    },
    {
        "id": "e7e4404be868efa6",
        "type": "inject",
        "z": "f6f2187d.f17ca8",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": true,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "11",
        "payloadType": "num",
        "x": 90,
        "y": 320,
        "wires": [
            [
                "dbf24e10071a9e79"
            ]
        ]
    },
    {
        "id": "cdc1d37295c1b69d",
        "type": "inject",
        "z": "f6f2187d.f17ca8",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": true,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "21",
        "payloadType": "num",
        "x": 90,
        "y": 380,
        "wires": [
            [
                "61d161c947337f69"
            ]
        ]
    },
    {
        "id": "66fee50b9e3f3475",
        "type": "inject",
        "z": "f6f2187d.f17ca8",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": true,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "0",
        "payloadType": "num",
        "x": 90,
        "y": 440,
        "wires": [
            [
                "bae823a10369d67f"
            ]
        ]
    },
    {
        "id": "9825f4157a4695ad",
        "type": "ui_button",
        "z": "f6f2187d.f17ca8",
        "name": "",
        "group": "91cf8ad51dd73124",
        "order": 2,
        "width": 0,
        "height": 0,
        "passthru": false,
        "label": "Setpoint 45",
        "tooltip": "",
        "color": "",
        "bgcolor": "",
        "className": "",
        "icon": "",
        "payload": "45",
        "payloadType": "num",
        "topic": "setpoint",
        "topicType": "str",
        "x": 270,
        "y": 200,
        "wires": [
            [
                "e0cb2a8c.4402a8",
                "cde7a23f3f468d3a"
            ]
        ]
    },
    {
        "id": "1060fbb819f76c93",
        "type": "ui_button",
        "z": "f6f2187d.f17ca8",
        "name": "",
        "group": "91cf8ad51dd73124",
        "order": 1,
        "width": 0,
        "height": 0,
        "passthru": false,
        "label": "Setpoint 55",
        "tooltip": "",
        "color": "",
        "bgcolor": "",
        "className": "",
        "icon": "",
        "payload": "55",
        "payloadType": "num",
        "topic": "setpoint",
        "topicType": "str",
        "x": 270,
        "y": 140,
        "wires": [
            [
                "e0cb2a8c.4402a8",
                "cde7a23f3f468d3a"
            ]
        ]
    },
    {
        "id": "2cfa00022a2bc7fe",
        "type": "inject",
        "z": "f6f2187d.f17ca8",
        "name": "cycle 1 second",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "1",
        "crontab": "",
        "once": true,
        "onceDelay": 0.1,
        "topic": "Cycle_1s",
        "payload": "0",
        "payloadType": "num",
        "x": 120,
        "y": 40,
        "wires": [
            [
                "dafcf5d27232fe72"
            ]
        ]
    },
    {
        "id": "dafcf5d27232fe72",
        "type": "link out",
        "z": "f6f2187d.f17ca8",
        "name": "Cycle_ 1s",
        "mode": "link",
        "links": [
            "2b4abc0e74db4c0e"
        ],
        "x": 255,
        "y": 40,
        "wires": []
    },
    {
        "id": "cde7a23f3f468d3a",
        "type": "function",
        "z": "f6f2187d.f17ca8",
        "name": "function 1",
        "func": "var setpoint = flow.get(\"setpoint\") || 45;\nif (msg.topic == \"setpoint\") {\n    flow.set(\"setpoint\", msg.payload);\n}\n//if (msg.topic == \"Cycle_1s\") {\n//    flow.set(\"setpoint\", 66);\n//}\nmsg.topic = \"Setpoint\";\nmsg.payload = flow.get(\"setpoint\");\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 620,
        "y": 140,
        "wires": [
            [
                "9f58a52d.076dd"
            ]
        ]
    },
    {
        "id": "2b4abc0e74db4c0e",
        "type": "link in",
        "z": "f6f2187d.f17ca8",
        "name": "link in 1",
        "links": [
            "dafcf5d27232fe72"
        ],
        "x": 525,
        "y": 100,
        "wires": [
            [
                "cde7a23f3f468d3a"
            ]
        ]
    },
    {
        "id": "dbf24e10071a9e79",
        "type": "ui_slider",
        "z": "f6f2187d.f17ca8",
        "name": "",
        "label": "Proportional band",
        "tooltip": "",
        "group": "38b0c5f8be13ea94",
        "order": 1,
        "width": 0,
        "height": 0,
        "passthru": false,
        "outs": "end",
        "topic": "prop_band",
        "topicType": "str",
        "min": 0,
        "max": "100",
        "step": 1,
        "className": "",
        "x": 290,
        "y": 320,
        "wires": [
            [
                "e0cb2a8c.4402a8"
            ]
        ]
    },
    {
        "id": "61d161c947337f69",
        "type": "ui_slider",
        "z": "f6f2187d.f17ca8",
        "name": "",
        "label": "Integration time",
        "tooltip": "",
        "group": "38b0c5f8be13ea94",
        "order": 2,
        "width": 0,
        "height": 0,
        "passthru": false,
        "outs": "end",
        "topic": "t_integral",
        "topicType": "str",
        "min": 0,
        "max": "1000",
        "step": 1,
        "className": "",
        "x": 280,
        "y": 380,
        "wires": [
            [
                "e0cb2a8c.4402a8"
            ]
        ]
    },
    {
        "id": "bae823a10369d67f",
        "type": "ui_slider",
        "z": "f6f2187d.f17ca8",
        "name": "",
        "label": "Differential time",
        "tooltip": "",
        "group": "38b0c5f8be13ea94",
        "order": 3,
        "width": 0,
        "height": 0,
        "passthru": false,
        "outs": "end",
        "topic": "t_derivative",
        "topicType": "str",
        "min": 0,
        "max": "1000",
        "step": 1,
        "className": "",
        "x": 280,
        "y": 440,
        "wires": [
            [
                "e0cb2a8c.4402a8"
            ]
        ]
    },
    {
        "id": "97854eece794f44d",
        "type": "debug",
        "z": "f6f2187d.f17ca8",
        "name": "debug 5",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 860,
        "y": 360,
        "wires": []
    },
    {
        "id": "6d2926a0440385e9",
        "type": "ui_button",
        "z": "f6f2187d.f17ca8",
        "name": "",
        "group": "91cf8ad51dd73124",
        "order": 3,
        "width": 0,
        "height": 0,
        "passthru": false,
        "label": "Manual",
        "tooltip": "",
        "color": "",
        "bgcolor": "",
        "className": "",
        "icon": "",
        "payload": "false",
        "payloadType": "bool",
        "topic": "enable",
        "topicType": "str",
        "x": 100,
        "y": 560,
        "wires": [
            [
                "c57f6d6f3e888353"
            ]
        ]
    },
    {
        "id": "a50b6aee5fe6a456",
        "type": "ui_button",
        "z": "f6f2187d.f17ca8",
        "name": "",
        "group": "91cf8ad51dd73124",
        "order": 4,
        "width": 0,
        "height": 0,
        "passthru": false,
        "label": "Auto",
        "tooltip": "",
        "color": "",
        "bgcolor": "",
        "className": "",
        "icon": "",
        "payload": "true",
        "payloadType": "bool",
        "topic": "enable",
        "topicType": "str",
        "x": 310,
        "y": 500,
        "wires": [
            [
                "e0cb2a8c.4402a8"
            ]
        ]
    },
    {
        "id": "54c8f8230ece1b8f",
        "type": "inject",
        "z": "f6f2187d.f17ca8",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": true,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "true",
        "payloadType": "bool",
        "x": 90,
        "y": 200,
        "wires": [
            [
                "9825f4157a4695ad"
            ]
        ]
    },
    {
        "id": "cd442369a8fb611f",
        "type": "link in",
        "z": "f6f2187d.f17ca8",
        "name": "Process Value",
        "links": [
            "23c0b4039a3399ab"
        ],
        "x": 325,
        "y": 260,
        "wires": [
            [
                "e0cb2a8c.4402a8",
                "de738fc5.75e4c8"
            ]
        ]
    },
    {
        "id": "4416d9ac4971e0c1",
        "type": "link out",
        "z": "f6f2187d.f17ca8",
        "name": "Controller Output",
        "mode": "link",
        "links": [
            "66070c91416cbb3a",
            "615c529cbe59fe25"
        ],
        "x": 695,
        "y": 360,
        "wires": []
    },
    {
        "id": "7e154912977853ce",
        "type": "delay",
        "z": "f6f2187d.f17ca8",
        "name": "",
        "pauseType": "rate",
        "timeout": "5",
        "timeoutUnits": "seconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": true,
        "allowrate": false,
        "outputs": 1,
        "x": 1030,
        "y": 320,
        "wires": [
            [
                "9f58a52d.076dd"
            ]
        ]
    },
    {
        "id": "5148e18ed7b309f3",
        "type": "function",
        "z": "f6f2187d.f17ca8",
        "name": "Mem Control Output",
        "func": "var ControllerOutput = flow.get(\"ControllerOutput\");\nflow.set(\"ControllerOutput\", msg.payload);\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 780,
        "y": 400,
        "wires": [
            []
        ]
    },
    {
        "id": "c57f6d6f3e888353",
        "type": "function",
        "z": "f6f2187d.f17ca8",
        "name": "Set Control Output",
        "func": "msg.enable = false;\nmsg.disabled_op = flow.get(\"ControllerOutput\");\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 270,
        "y": 560,
        "wires": [
            [
                "e0cb2a8c.4402a8"
            ]
        ]
    },
    {
        "id": "30129dbd31954216",
        "type": "ui_slider",
        "z": "f6f2187d.f17ca8",
        "name": "",
        "label": "Controller Output",
        "tooltip": "",
        "group": "91cf8ad51dd73124",
        "order": 5,
        "width": 0,
        "height": 0,
        "passthru": false,
        "outs": "end",
        "topic": "disabled_op",
        "topicType": "str",
        "min": 0,
        "max": "100",
        "step": "1",
        "className": "",
        "x": 270,
        "y": 620,
        "wires": [
            [
                "9a94cb8defbd4b30"
            ]
        ]
    },
    {
        "id": "615c529cbe59fe25",
        "type": "link in",
        "z": "f6f2187d.f17ca8",
        "name": "link in 3",
        "links": [
            "4416d9ac4971e0c1"
        ],
        "x": 25,
        "y": 620,
        "wires": [
            [
                "26aa264556f4b565"
            ]
        ]
    },
    {
        "id": "26aa264556f4b565",
        "type": "range",
        "z": "f6f2187d.f17ca8",
        "minin": "0",
        "maxin": "1",
        "minout": "0",
        "maxout": "100",
        "action": "scale",
        "round": false,
        "property": "payload",
        "name": "Scale",
        "x": 110,
        "y": 620,
        "wires": [
            [
                "30129dbd31954216"
            ]
        ]
    },
    {
        "id": "9a94cb8defbd4b30",
        "type": "range",
        "z": "f6f2187d.f17ca8",
        "minin": "0",
        "maxin": "100",
        "minout": "0",
        "maxout": "1",
        "action": "scale",
        "round": false,
        "property": "payload",
        "name": "Scale",
        "x": 430,
        "y": 620,
        "wires": [
            [
                "e0cb2a8c.4402a8"
            ]
        ]
    },
    {
        "id": "4d3106d42c84229a",
        "type": "subflow:b4973237.46ab6",
        "z": "3fa8ce724cad2896",
        "name": "",
        "x": 330,
        "y": 140,
        "wires": [
            [
                "1e39139809dc14a3"
            ]
        ]
    },
    {
        "id": "23c0b4039a3399ab",
        "type": "link out",
        "z": "3fa8ce724cad2896",
        "name": "Process Value",
        "mode": "link",
        "links": [
            "cd442369a8fb611f"
        ],
        "x": 745,
        "y": 140,
        "wires": []
    },
    {
        "id": "66070c91416cbb3a",
        "type": "link in",
        "z": "3fa8ce724cad2896",
        "name": "link in 2",
        "links": [
            "4416d9ac4971e0c1"
        ],
        "x": 135,
        "y": 140,
        "wires": [
            [
                "4d3106d42c84229a"
            ]
        ]
    },
    {
        "id": "1e39139809dc14a3",
        "type": "delay",
        "z": "3fa8ce724cad2896",
        "name": "",
        "pauseType": "rate",
        "timeout": "5",
        "timeoutUnits": "seconds",
        "rate": "4",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": true,
        "allowrate": false,
        "outputs": 1,
        "x": 550,
        "y": 140,
        "wires": [
            [
                "23c0b4039a3399ab"
            ]
        ]
    }
]