Controller tuning on EVCS

Final flow below.

Blew out the cycle time due to massive system deadtime, and therefore unclamped the step changes. Works pretty good, rarely overshoots. Deadtime is the problem.

[
   {
       "id": "5685784aca024950",
       "type": "group",
       "z": "4ff6b2cd6a13dee2",
       "style": {
           "stroke": "#999999",
           "stroke-opacity": "1",
           "fill": "none",
           "fill-opacity": "1",
           "label": true,
           "label-position": "nw",
           "color": "#a4a4a4"
       },
       "nodes": [
           "73a7784ccc1b856e",
           "2165a2ec52a7493a",
           "a224484edd3caa68",
           "02df2203613031a6",
           "9c1c4e6a3595812d",
           "5a3e4f13289adb9d",
           "16a3523b03a5c9eb",
           "30490cdf75624db9",
           "119ebe0f36b5d112",
           "89fb13aa835d6a53",
           "64aac72d92efc1c1",
           "18a98b02fb0b66fd",
           "05ce637569480b5b",
           "b2b662a4db1dd2c4",
           "b0a2769c7666fd88",
           "a56417d984ca4a48",
           "0194a03d5ddaeffc",
           "7adc0ccc5669cf5c",
           "b62932fd2348d1ed",
           "1bf48d983a61cd02",
           "check_status_bess_soc",
           "6eaf03afa07d188f",
           "aa82e2b5e3f8feb1",
           "04b2fb5c53805f27",
           "ca74453c62dee76d",
           "369180560863d5e4",
           "e07eed9cdcb76804",
           "aad15c9e95779da0",
           "c9059899bf816cca"
       ],
       "x": 14,
       "y": 19,
       "w": 892,
       "h": 582
   },
   {
       "id": "73a7784ccc1b856e",
       "type": "function",
       "z": "4ff6b2cd6a13dee2",
       "g": "5685784aca024950",
       "name": "Set Setpoint",
       "func": "flow.set('setpoint', msg.payload);\nreturn null;",
       "outputs": 1,
       "timeout": "",
       "noerr": 0,
       "initialize": "",
       "finalize": "",
       "libs": [],
       "x": 810,
       "y": 180,
       "wires": [
           []
       ]
   },
   {
       "id": "2165a2ec52a7493a",
       "type": "function",
       "z": "4ff6b2cd6a13dee2",
       "g": "5685784aca024950",
       "name": "Calculate",
       "func": "// Helper function to ensure a value is a number\nfunction toNumber(value, defaultVal) {\n    let num = Number(value);\n    return isNaN(num) || value === null || value === undefined ? defaultVal : num;\n}\n\n// Check if the message contains charger power (from EV Charger W)\nif (msg.topic === 'charger_power') {\n    // Store the charger power in flow context\n    let chargerPower = toNumber(msg.payload, 0); // Default to 0W if invalid\n    flow.set('charger_power', chargerPower);\n    return null; // Don't process this message further\n}\n\n// Retrieve charger power from flow context\nlet chargerPower = toNumber(flow.get('charger_power'), 0); // Default to 0W if not set\n\n// Retrieve charger current (A) from the EV Charger input (from EV Charger A)\nlet current_output_amps = toNumber(msg.payload, 6); // Default to 6A if invalid\nflow.set('current_output_amps', current_output_amps);\n\n// Retrieve context variables with robust defaults\nlet previous_output_amps = toNumber(flow.get('previous_output_amps'), 6); // Default 6A\nlet last_set_amps = toNumber(flow.get('last_set_amps'), 6); // Default 6A\nlet bess_charge_rate = toNumber(flow.get('bess_charge_rate'), 0); // Default 0W\nlet setpoint = toNumber(flow.get('setpoint'), 150); // Default 150W\n\n// Calculate the deviation from the setpoint (available_power)\nlet available_power = bess_charge_rate - setpoint;\nlet deviation = Math.abs(available_power); // Absolute deviation in watts\n\n// Determine the cycle time based on deviation\nlet cycleTime;\nif (deviation > 2600) {\n    cycleTime = 6000; \n} else if (deviation > 1200 && deviation <= 2000) {\n    cycleTime = 5000; \n} else if (deviation > 800 && deviation <= 1200) {\n    cycleTime = 6000;\n} else {\n    cycleTime = 8000;\n}\n\n// Check the last calculation time\nlet lastCalcTime = flow.get('lastCalcTime') || 0; // Default to 0 if not set\nlet currentTime = Date.now();\nlet timeSinceLastCalc = currentTime - lastCalcTime; // Time in milliseconds\n\n// Only calculate if the cycle time has elapsed\nif (timeSinceLastCalc < cycleTime) {\n    return null; // Skip the calculation\n}\n\n// Update the last calculation time\nflow.set('lastCalcTime', currentTime);\n\n// Calculate target amps with raw BESS charge rate\nlet voltage = 240; // System voltage\nlet target_amps = Math.round(Math.max(6, Math.min(30, (available_power / voltage) + current_output_amps)) *5) /5;\n\n// Calculate change\nlet change_in_output = target_amps - current_output_amps;\n\n// If change < 0.5A, don’t update (reduced deadband)\nif (Math.abs(change_in_output) < 1) {\n    return null;\n}\n\n// Dynamic clamp based on deviation from setpoint\nlet clamp_limit = 5; // Default value;\nif (deviation <= 750) {\n    clamp_limit = 3; \n} else if (deviation > 750 && deviation <= 1250) {\n    clamp_limit = 5; \n} else if (deviation > 1250 && deviation <=2400) {\n    clamp_limit = 7;\n} else if (deviation >2400) {\n    clamp_limit = 12;\n}\n\nlet clamped_change = Math.max(-clamp_limit, Math.min(change_in_output, clamp_limit));\nlet new_output_amps = Math.max(5, Math.min(26,current_output_amps + clamped_change));\n\n\n// Go straight to setpoint on startup.\nif (chargerPower <= 1100) {\n    new_output_amps = Math.max(6, Math.min(30, (bess_charge_rate / voltage) * .5));\n}\n\n// Round to 0 decimal places\nnew_output_amps = Math.round(new_output_amps);\nflow.set('last_set_amps', new_output_amps);\n\n// Display status instead of logging\nnode.status({ fill: \"green\", shape: \"dot\", text: `Previous: ${previous_output_amps.toFixed(1)}A, Delta: ${deviation.toFixed(0)}W, SP: ${setpoint.toFixed(0)}` });\n\n\n// Update context\nflow.set('previous_output_amps', new_output_amps);\n\n\n\n// Set output\nmsg.payload = new_output_amps;\n\nreturn msg;",
       "outputs": 1,
       "timeout": "",
       "noerr": 0,
       "initialize": "",
       "finalize": "",
       "libs": [],
       "x": 620,
       "y": 440,
       "wires": [
           [
               "02df2203613031a6",
               "369180560863d5e4"
           ]
       ]
   },
   {
       "id": "a224484edd3caa68",
       "type": "victron-input-system",
       "z": "4ff6b2cd6a13dee2",
       "g": "5685784aca024950",
       "service": "com.victronenergy.system/0",
       "path": "/Dc/Battery/Power",
       "serviceObj": {
           "service": "com.victronenergy.system/0",
           "name": "Venus system"
       },
       "pathObj": {
           "path": "/Dc/Battery/Power",
           "type": "float",
           "name": "Battery Power (W)"
       },
       "name": "BESS charge rate",
       "onlyChanges": false,
       "x": 130,
       "y": 240,
       "wires": [
           [
               "6eaf03afa07d188f",
               "aa82e2b5e3f8feb1"
           ]
       ],
       "icon": "font-awesome/fa-battery-4"
   },
   {
       "id": "02df2203613031a6",
       "type": "victron-output-evcharger",
       "z": "4ff6b2cd6a13dee2",
       "g": "5685784aca024950",
       "service": "com.victronenergy.evcharger/40",
       "path": "/SetCurrent",
       "serviceObj": {
           "service": "com.victronenergy.evcharger/40",
           "name": "Me Charger"
       },
       "pathObj": {
           "path": "/SetCurrent",
           "type": "float",
           "name": "Set charge current (manual mode) (A)",
           "writable": true
       },
       "initial": 6,
       "name": "Set EV Charger",
       "onlyChanges": false,
       "x": 800,
       "y": 420,
       "wires": [],
       "icon": "font-awesome/fa-automobile"
   },
   {
       "id": "9c1c4e6a3595812d",
       "type": "function",
       "z": "4ff6b2cd6a13dee2",
       "g": "5685784aca024950",
       "name": "Set BESS charge rate",
       "func": "let bess_charge_rate = msg.payload;\nflow.set('bess_charge_rate', bess_charge_rate);\nreturn msg;",
       "outputs": 1,
       "timeout": 0,
       "noerr": 0,
       "initialize": "",
       "finalize": "",
       "libs": [],
       "x": 780,
       "y": 240,
       "wires": [
           []
       ]
   },
   {
       "id": "5a3e4f13289adb9d",
       "type": "victron-input-system",
       "z": "4ff6b2cd6a13dee2",
       "g": "5685784aca024950",
       "service": "com.victronenergy.system/0",
       "path": "/Dc/Battery/Soc",
       "serviceObj": {
           "service": "com.victronenergy.system/0",
           "name": "Venus system"
       },
       "pathObj": {
           "path": "/Dc/Battery/Soc",
           "type": "float",
           "name": "Battery State of Charge (%)"
       },
       "name": "BESS SoC",
       "onlyChanges": false,
       "roundValues": "no",
       "x": 100,
       "y": 180,
       "wires": [
           [
               "check_status_bess_soc"
           ]
       ],
       "icon": "font-awesome/fa-battery-3"
   },
   {
       "id": "16a3523b03a5c9eb",
       "type": "victron-input-vebus",
       "z": "4ff6b2cd6a13dee2",
       "g": "5685784aca024950",
       "service": "com.victronenergy.vebus/276",
       "path": "/Ac/Out/L1/F",
       "serviceObj": {
           "service": "com.victronenergy.vebus/276",
           "name": "MultiPlus-II 48/5000/70-50"
       },
       "pathObj": {
           "path": "/Ac/Out/L1/F",
           "type": "float",
           "name": "Output frequency phase 1 (Hz)"
       },
       "name": "Frequency",
       "onlyChanges": false,
       "roundValues": "2",
       "x": 100,
       "y": 120,
       "wires": [
           [
               "30490cdf75624db9"
           ]
       ],
       "icon": "font-awesome/fa-sun-o"
   },
   {
       "id": "30490cdf75624db9",
       "type": "function",
       "z": "4ff6b2cd6a13dee2",
       "g": "5685784aca024950",
       "name": "Frequency set",
       "func": "let frequency = msg.payload;\nflow.set('frequency', frequency);\nreturn msg;",
       "outputs": 1,
       "timeout": 0,
       "noerr": 0,
       "initialize": "",
       "finalize": "",
       "libs": [],
       "x": 800,
       "y": 120,
       "wires": [
           []
       ]
   },
   {
       "id": "119ebe0f36b5d112",
       "type": "victron-output-evcharger",
       "z": "4ff6b2cd6a13dee2",
       "g": "5685784aca024950",
       "service": "com.victronenergy.evcharger/40",
       "path": "/StartStop",
       "serviceObj": {
           "service": "com.victronenergy.evcharger/40",
           "name": "Me Charger"
       },
       "pathObj": {
           "path": "/StartStop",
           "type": "enum",
           "name": "Start/stop charging (manual mode)",
           "enum": {
               "0": "Stop",
               "1": "Start"
           },
           "writable": true
       },
       "initial": 1,
       "name": "EV Charger On/Off",
       "onlyChanges": false,
       "x": 790,
       "y": 360,
       "wires": [],
       "icon": "font-awesome/fa-automobile"
   },
   {
       "id": "89fb13aa835d6a53",
       "type": "function",
       "z": "4ff6b2cd6a13dee2",
       "g": "5685784aca024950",
       "name": "-300W Turn Off Timer",
       "func": "// Get the current battery charge rate (W) from msg.payload (from /Dc/Battery/Power)\nlet bess_charge_rate = Number(msg.payload);\n\n// Constants\nconst MIN_CHARGE = -300; // Minimum charge rate threshold (W)\nconst RESET_THRESHOLD = -200; // Reset timer if charge rate rises above this (W)\nconst DURATION_MINUTES = 10; // Duration in minutes\nconst DURATION_MS = DURATION_MINUTES * 60 * 1000; // Convert to milliseconds (20 minutes = 1,200,000 ms)\nconst LOG_INTERVAL_MS = 3 * 60 * 1000; // Log every 5 minutes (300,000 ms)\n\n// Get the current time\nlet currentTime = Date.now();\n\n// Retrieve the start time and last log time from flow context (null if not set)\nlet startTimeAtMinus300W = flow.get('startTimeAtMinus300W') || null;\nlet lastLogTime = flow.get('lastLogTimeAtMinus300W') || 0;\n\n// Check if the battery charge rate is below -300W\nif (bess_charge_rate < MIN_CHARGE) {\n    if (startTimeAtMinus300W === null) {\n        // Start the timer if it hasn't been started\n        startTimeAtMinus300W = currentTime;\n        flow.set('startTimeAtMinus300W', startTimeAtMinus300W);\n        flow.set('lastLogTimeAtMinus300W', currentTime); // Reset last log time\n        node.status(`Started timer for charge rate below -300W at ${new Date(startTimeAtMinus300W).toISOString()}`);\n    } else {\n        // Calculate elapsed time\n        let elapsedTime = currentTime - startTimeAtMinus300W;\n\n        // Log elapsed time only every 5 minutes\n        if (currentTime - lastLogTime >= LOG_INTERVAL_MS) {\n            node.warn(`Charge rate below -300W for ${Math.floor(elapsedTime / 1000)} seconds`);\n            flow.set('lastLogTimeAtMinus300W', currentTime);\n        }\n\n        // Check if 10 minutes have passed\n        if (elapsedTime >= DURATION_MS) {\n            node.status(`Charge rate has been below -300W for ${DURATION_MINUTES} minutes, stopping charger`);\n            // Send 0 to stop charging\n            msg.payload = 0;\n            // Reset the timer and last log time\n            flow.set('startTimeAtMinus300W', null);\n            flow.set('lastLogTimeAtMinus300W', 0);\n            return msg; // Send the stop command to the Stop charging node\n        }\n    }\n} else {\n    // If charge rate rises above the reset threshold, reset the timer\n    if (startTimeAtMinus300W !== null && bess_charge_rate >= RESET_THRESHOLD) {\n        node.status(`Charge rate risen to ${bess_charge_rate}W, resetting -300W timer`);\n        flow.set('startTimeAtMinus300W', null);\n        flow.set('lastLogTimeAtMinus300W', 0);\n    }\n}\n\n// If no stop command or start command is needed, return null\nreturn null;\n",
       "outputs": 1,
       "timeout": "",
       "noerr": 0,
       "initialize": "",
       "finalize": "",
       "libs": [],
       "x": 520,
       "y": 260,
       "wires": [
           [
               "119ebe0f36b5d112"
           ]
       ]
   },
   {
       "id": "64aac72d92efc1c1",
       "type": "inject",
       "z": "4ff6b2cd6a13dee2",
       "g": "5685784aca024950",
       "name": "Stop charging",
       "props": [
           {
               "p": "payload"
           },
           {
               "p": "topic",
               "vt": "str"
           }
       ],
       "repeat": "",
       "crontab": "",
       "once": false,
       "onceDelay": 0.1,
       "topic": "",
       "payload": "0",
       "payloadType": "num",
       "x": 270,
       "y": 400,
       "wires": [
           [
               "119ebe0f36b5d112"
           ]
       ]
   },
   {
       "id": "18a98b02fb0b66fd",
       "type": "inject",
       "z": "4ff6b2cd6a13dee2",
       "g": "5685784aca024950",
       "name": "Start charging",
       "props": [
           {
               "p": "payload"
           },
           {
               "p": "topic",
               "vt": "str"
           }
       ],
       "repeat": "",
       "crontab": "",
       "once": false,
       "onceDelay": 0.1,
       "topic": "",
       "payload": "1",
       "payloadType": "num",
       "x": 270,
       "y": 360,
       "wires": [
           [
               "119ebe0f36b5d112"
           ]
       ]
   },
   {
       "id": "05ce637569480b5b",
       "type": "victron-input-evcharger",
       "z": "4ff6b2cd6a13dee2",
       "g": "5685784aca024950",
       "service": "com.victronenergy.evcharger/40",
       "path": "/Status",
       "serviceObj": {
           "service": "com.victronenergy.evcharger/40",
           "name": "Me Charger"
       },
       "pathObj": {
           "path": "/Status",
           "type": "enum",
           "name": "Status",
           "enum": {
               "0": "Disconnected",
               "1": "Connected",
               "2": "Charging",
               "3": "Charged",
               "4": "Waiting for sun",
               "5": "Waiting for RFID",
               "6": "Waiting for start",
               "7": "Low SOC",
               "8": "Ground test error",
               "9": "Welded contacts test error",
               "10": "CP input test error (shorted)",
               "11": "Residual current detected",
               "12": "Undervoltage detected",
               "13": "Overvoltage detected",
               "14": "Overheating detected",
               "15": "Reserved",
               "16": "Reserved",
               "17": "Reserved",
               "18": "Reserved",
               "19": "Reserved",
               "20": "Charging limit",
               "21": "Start charging",
               "22": "Switching to 3 phase",
               "23": "Switching to 1 phase",
               "24": "Stop charging"
           }
       },
       "initial": "",
       "name": "Charger Status",
       "onlyChanges": true,
       "x": 120,
       "y": 60,
       "wires": [
           [
               "b2b662a4db1dd2c4"
           ]
       ],
       "icon": "font-awesome/fa-car"
   },
   {
       "id": "b2b662a4db1dd2c4",
       "type": "function",
       "z": "4ff6b2cd6a13dee2",
       "g": "5685784aca024950",
       "name": "Status set",
       "func": "if (msg.topic === \"auto\") {\n    return null; // Return null if topic is \"auto\"\n} else {\n    let status = msg.payload;\n    flow.set('status', status);\n}\nreturn msg;",
       "outputs": 1,
       "timeout": 0,
       "noerr": 0,
       "initialize": "",
       "finalize": "",
       "libs": [],
       "x": 820,
       "y": 60,
       "wires": [
           []
       ]
   },
   {
       "id": "b0a2769c7666fd88",
       "type": "victron-input-evcharger",
       "z": "4ff6b2cd6a13dee2",
       "g": "5685784aca024950",
       "service": "com.victronenergy.evcharger/40",
       "path": "/Current",
       "serviceObj": {
           "service": "com.victronenergy.evcharger/40",
           "name": "Me Charger"
       },
       "pathObj": {
           "path": "/Current",
           "type": "float",
           "name": "Charge current (A)"
       },
       "name": "EV Charger A",
       "onlyChanges": false,
       "roundValues": "0",
       "x": 110,
       "y": 440,
       "wires": [
           [
               "0194a03d5ddaeffc"
           ]
       ],
       "icon": "font-awesome/fa-automobile"
   },
   {
       "id": "a56417d984ca4a48",
       "type": "function",
       "z": "4ff6b2cd6a13dee2",
       "g": "5685784aca024950",
       "name": "SP by soc & freq",
       "func": "// Helper function to ensure a value is a number\n    function toNumber(value, defaultVal) {\n        let num = Number(value);\n        return isNaN(num) || value === null || value === undefined ? defaultVal : num;\n    }\n\n    // Get the SoC from msg.payload\n    let soc = toNumber(msg.payload, 0); // Default to 0 if invalid\n    \n    if (msg.topic = \"startup\") {\n        initialsetpoint = ((100 - soc) * 150/6) || 500;\n    }\n    \n // Use stored setpoint or default for SoC < 90\n        if (soc < 90) {\n            setpoint = initialsetpoint || 450; // Use initial setpoint or default\n        } else if (soc >= 90 && soc < 96) {\n            setpoint = 300; // 90 ≤ SoC ≤ 97\n        } else if (soc >= 96 && soc <= 98) {\n            setpoint = 200; // 97 ≤ SoC ≤ 98\n        } else if (soc > 98 && soc < 100) {\n            setpoint = 70; // 98 < SoC ≤ 99.4\n        } else {\n            setpoint = -150; // SoC > 99.4\n        }\n\n    // Retrieve frequency from flow context\n    let frequency = flow.get('frequency') || 50; // Default to 50Hz\n\n    // Override setpoint if frequency > 50.2\n    if (frequency > 50.2) {\n        setpoint = -500;\n        node.warn(`Frequency ${frequency}Hz > 50.2Hz, overriding setpoint to ${setpoint}W`);\n    }\n\n    node.status({ fill: \"green\", shape: \"dot\", text: `SP: ${setpoint.toFixed(0)}W` });\n\n    // Set the output payload to the setpoint\n    msg.payload = setpoint;\n\n    return msg;",
       "outputs": 1,
       "timeout": 0,
       "noerr": 0,
       "initialize": "",
       "finalize": "",
       "libs": [],
       "x": 430,
       "y": 180,
       "wires": [
           [
               "73a7784ccc1b856e"
           ]
       ]
   },
   {
       "id": "0194a03d5ddaeffc",
       "type": "function",
       "z": "4ff6b2cd6a13dee2",
       "g": "5685784aca024950",
       "name": "Check",
       "func": "// Retrieve the charger status from flow context\nlet status = flow.get('status') || 0; // Default to 0 (Disconnected) if not set\n\n// Check if status is 2 (Charging) or 21 (Start charging)\nif (status === 2 || status === 21) {\n    return msg; // Pass the message through\n} else {\n    return null; // Block the message\n}",
       "outputs": 1,
       "timeout": "",
       "noerr": 0,
       "initialize": "",
       "finalize": "",
       "libs": [],
       "x": 290,
       "y": 440,
       "wires": [
           [
               "2165a2ec52a7493a"
           ]
       ]
   },
   {
       "id": "7adc0ccc5669cf5c",
       "type": "victron-input-evcharger",
       "z": "4ff6b2cd6a13dee2",
       "g": "5685784aca024950",
       "service": "com.victronenergy.evcharger/40",
       "path": "/Ac/L1/Power",
       "serviceObj": {
           "service": "com.victronenergy.evcharger/40",
           "name": "Me Charger"
       },
       "pathObj": {
           "path": "/Ac/L1/Power",
           "type": "float",
           "name": "L1 Power (W)"
       },
       "name": "EV Charger W",
       "onlyChanges": false,
       "roundValues": "0",
       "x": 110,
       "y": 500,
       "wires": [
           [
               "1bf48d983a61cd02"
           ]
       ],
       "icon": "font-awesome/fa-automobile"
   },
   {
       "id": "b62932fd2348d1ed",
       "type": "change",
       "z": "4ff6b2cd6a13dee2",
       "g": "5685784aca024950",
       "name": "Initialise input",
       "rules": [
           {
               "t": "set",
               "p": "topic",
               "pt": "msg",
               "to": "charger_power",
               "tot": "str"
           }
       ],
       "action": "",
       "property": "",
       "from": "",
       "to": "",
       "reg": false,
       "x": 400,
       "y": 500,
       "wires": [
           [
               "2165a2ec52a7493a"
           ]
       ]
   },
   {
       "id": "1bf48d983a61cd02",
       "type": "function",
       "z": "4ff6b2cd6a13dee2",
       "g": "5685784aca024950",
       "name": "Check",
       "func": "// Retrieve the charger status from flow context\nlet status = flow.get('status') || 0; // Default to 0 (Disconnected) if not set\n\n// Check if status is 2 (Charging) or 21 (Start charging)\nif (status === 2 || status === 21) {\n    return msg; // Pass the message through\n} else {\n    return null; // Block the message\n}",
       "outputs": 1,
       "timeout": "",
       "noerr": 0,
       "initialize": "",
       "finalize": "",
       "libs": [],
       "x": 250,
       "y": 500,
       "wires": [
           [
               "b62932fd2348d1ed"
           ]
       ]
   },
   {
       "id": "check_status_bess_soc",
       "type": "function",
       "z": "4ff6b2cd6a13dee2",
       "g": "5685784aca024950",
       "name": "Check",
       "func": "// Retrieve the charger status from flow context\nlet status = flow.get('status') || 0; // Default to 0 (Disconnected) if not set\n\n// Check if status is 2 (Charging) or 21 (Start charging)\nif (status === 2 || status === 21) {\n    if (status === 21) {\n            msg.topic = \"startup\";\n        }\n    return msg; // Pass the message through\n} else {\n    return null; // Block the message\n}",
       "outputs": 1,
       "timeout": "",
       "noerr": 0,
       "initialize": "",
       "finalize": "",
       "libs": [],
       "x": 250,
       "y": 180,
       "wires": [
           [
               "a56417d984ca4a48"
           ]
       ]
   },
   {
       "id": "6eaf03afa07d188f",
       "type": "function",
       "z": "4ff6b2cd6a13dee2",
       "g": "5685784aca024950",
       "name": "Check",
       "func": "// Retrieve the charger status from flow context\nlet status = flow.get('status') || 0; // Default to 0 (Disconnected) if not set\n\n// Check if status is 2 (Charging) or 21 (Start charging)\nif (status === 2 || status === 21) {\n    return msg; // Pass the message through\n} else {\n    return null; // Block the message\n}",
       "outputs": 1,
       "timeout": "",
       "noerr": 0,
       "initialize": "",
       "finalize": "",
       "libs": [],
       "x": 310,
       "y": 240,
       "wires": [
           [
               "89fb13aa835d6a53",
               "9c1c4e6a3595812d"
           ]
       ]
   },
   {
       "id": "aa82e2b5e3f8feb1",
       "type": "function",
       "z": "4ff6b2cd6a13dee2",
       "g": "5685784aca024950",
       "name": "Check",
       "func": "// Retrieve the charger status from flow context\nlet status = flow.get('status') || 0; // Default to 0 (Disconnected) if not set\n\n// Check if status is 6\nif (status === 6) {\n    return msg; // Pass the message through\n} else {\n    return null; // Block the message\n}",
       "outputs": 1,
       "timeout": "",
       "noerr": 0,
       "initialize": "",
       "finalize": "",
       "libs": [],
       "x": 310,
       "y": 280,
       "wires": [
           [
               "04b2fb5c53805f27"
           ]
       ]
   },
   {
       "id": "04b2fb5c53805f27",
       "type": "function",
       "z": "4ff6b2cd6a13dee2",
       "g": "5685784aca024950",
       "name": "Restart on Frequency",
       "func": "\nconst FREQUENCY_THRESHOLD = 50.2; // Frequency threshold for start command\n\n// Retrieve frequency from flow context\nlet frequency = flow.get('frequency') || 50; // Default to 50Hz\n\nif (frequency > FREQUENCY_THRESHOLD) {\n    // Send a start command if frequency is above 50.2\n    msg.payload = \"1\";\n    return msg; // Send the start command to the next node\n}\n",
       "outputs": 1,
       "timeout": "",
       "noerr": 0,
       "initialize": "",
       "finalize": "",
       "libs": [],
       "x": 520,
       "y": 320,
       "wires": [
           [
               "119ebe0f36b5d112"
           ]
       ]
   },
   {
       "id": "ca74453c62dee76d",
       "type": "inject",
       "z": "4ff6b2cd6a13dee2",
       "g": "5685784aca024950",
       "name": "",
       "props": [
           {
               "p": "payload"
           }
       ],
       "repeat": "",
       "crontab": "",
       "once": false,
       "onceDelay": 0.1,
       "topic": "",
       "payload": "100",
       "payloadType": "num",
       "x": 470,
       "y": 140,
       "wires": [
           [
               "73a7784ccc1b856e"
           ]
       ]
   },
   {
       "id": "369180560863d5e4",
       "type": "debug",
       "z": "4ff6b2cd6a13dee2",
       "g": "5685784aca024950",
       "name": "History",
       "active": true,
       "tosidebar": true,
       "console": false,
       "tostatus": false,
       "complete": "payload",
       "targetType": "msg",
       "statusVal": "",
       "statusType": "auto",
       "x": 800,
       "y": 500,
       "wires": []
   },
   {
       "id": "e07eed9cdcb76804",
       "type": "victron-input-evcharger",
       "z": "4ff6b2cd6a13dee2",
       "g": "5685784aca024950",
       "service": "com.victronenergy.evcharger/40",
       "path": "/Mode",
       "serviceObj": {
           "service": "com.victronenergy.evcharger/40",
           "name": "Me Charger"
       },
       "pathObj": {
           "path": "/Mode",
           "type": "enum",
           "name": "Mode",
           "enum": {
               "0": "Manual",
               "1": "Auto",
               "2": "Schedule"
           }
       },
       "initial": "",
       "name": "",
       "onlyChanges": false,
       "x": 310,
       "y": 80,
       "wires": [
           [
               "aad15c9e95779da0"
           ]
       ]
   },
   {
       "id": "aad15c9e95779da0",
       "type": "function",
       "z": "4ff6b2cd6a13dee2",
       "g": "5685784aca024950",
       "name": "Auto end calc",
       "func": "if (msg.payload = 1) {\n    msg.topic = \"auto\";\n    return msg; // Send the start command to the next node\n}",
       "outputs": 1,
       "timeout": 0,
       "noerr": 0,
       "initialize": "",
       "finalize": "",
       "libs": [],
       "x": 540,
       "y": 80,
       "wires": [
           [
               "b2b662a4db1dd2c4"
           ]
       ]
   },
   {
       "id": "c9059899bf816cca",
       "type": "victron-input-vebus",
       "z": "4ff6b2cd6a13dee2",
       "g": "5685784aca024950",
       "service": "com.victronenergy.vebus/276",
       "path": "/Ac/Out/L1/V",
       "serviceObj": {
           "service": "com.victronenergy.vebus/276",
           "name": "MultiPlus-II 48/5000/70-50"
       },
       "pathObj": {
           "path": "/Ac/Out/L1/V",
           "type": "float",
           "name": "Output voltage phase 1 (VAC)"
       },
       "name": "",
       "onlyChanges": false,
       "roundValues": "1",
       "x": 250,
       "y": 560,
       "wires": [
           []
       ]
   }
]