1. Trouble with the game?
    Try the troubleshooter!

    Dismiss Notice
  2. Issues with the game?
    Check the Known Issues list before reporting!

    Dismiss Notice
  3. Before reporting issues or bugs, please check the up-to-date Bug Reporting Thread for the current version.
    0.36 Bug Reporting thread
    Solutions and more information may already be available.

Dynamic ECU Problem

Discussion in 'Troubleshooting: Bugs, Questions and Support' started by Arm-Leg, Jun 25, 2025 at 9:28 PM.

  1. Arm-Leg

    Arm-Leg
    Expand Collapse

    Joined:
    Mar 19, 2022
    Messages:
    11
    Hi everyone,

    I'm working on a mod for the ETK I-Series to allow dynamic switching of ECU characteristics, similar to changing engine maps. I've set up a system where:

    1. An "advanced" ECU JBeam part (etki_engine_ecu_advanced_diesel.jbeam) contains conditional logic to change mainEngine parameters (torque curve, idleRPM, particulates, burnEfficiency) based on the value of electrics.values.ecu_profile.

    2. A custom Lua vehicle controller (etkECUProfileController.lua) successfully sets electrics.values.ecu_profile to 1 (for an "EVRY" tune) or 2 (for a "Standard" tune) when its functions are called via the console.
    The Problem:
    Even though I can confirm with console prints that electrics.values.ecu_profile is being correctly set to 1 or 2 by my Lua controller, the actual engine behavior (power, idle speed, sound/smoke from particulates) does not appear to change in-game.

    What I've Verified:

    • Is being set correctly:
      • Calling extensions.etkECUProfileController.setProfileEVRY() sets electrics.values.ecu_profile to 1.

      • Calling extensions.etkECUProfileController.setProfileStandard() sets electrics.values.ecu_profile to 2.

      • print(electrics.values.ecu_profile) in the Vehicle Lua console reflects these changes immediately.
    • Conditional Lua Logic in JBeam Expressions is Correct:
      • I've tested the Lua expressions from my ECU's JBeam directly in the Vehicle Lua console after setting ecu_profile. They evaluate to the correct numerical values for the active profile (e.g., EVRY torque values when ecu_profile is 1, nil for those torque points when ecu_profile is 2).

      • For example, when electrics.values.ecu_profile = 1, the expression print(not (electrics and electrics.values and electrics.values.ecu_profile == 2) and 191 or nil) correctly prints 191.

      • When electrics.values.ecu_profile = 2, the same expression correctly prints nil.

      • This applies to torque points, $+idleRPM additions, burnEfficiency points, etc.
    • No Obvious JBeam Syntax Errors: The game is loading without JBeam parsing errors related to these files now.

    • Custom Lua Controller: (Included below - it's very simple)
    The Question:
    Why would the mainEngine parameters defined in my etki_engine_ecu_advanced_diesel.jbeam not dynamically update when the Lua conditions within its JBeam expressions are evaluating correctly based on a changing electrics.values.ecu_profile? Is there a specific way mainEngine parameters are cached or updated that I'm missing, or something that would prevent the ECU JBeam from overriding/modifying them dynamically in this manner?

    I know JBeam can dynamically adjust parameters (e.g., turbos reacting to electrics), so I'm a bit stumped as to why these core engine characteristics aren't changing.

    Console Log Snippet (showing Lua controller setting ecu_profile and expressions evaluating correctly):

    GELua.ui_console.exec|veh 30453 < "extensions.etkECUProfileController.setProfileEVRY()"
    libbeamng.etkECUProfileController|Attempting to set EVRY Profile (1)
    libbeamng.etkECUProfileController|ecu_profile set to: 1
    GELua.ui_console.exec|veh 30453 < "print(not (electrics and electrics.values and electrics.values.ecu_profile == 2) and 5 or 0)"
    libbeamng.print|5
    GELua.ui_console.exec|veh 30453 < "extensions.etkECUProfileController.setProfileStandard()"
    libbeamng.etkECUProfileController|Attempting to set Standard Profile (2)
    libbeamng.etkECUProfileController|ecu_profile set to: 2
    GELua.ui_console.exec|veh 30453 < "print(not (electrics and electrics.values and electrics.values.ecu_profile == 2) and 5 or 0)"
    libbeamng.print|0

    Any insights or suggestions on what might be preventing the JBeam from dynamically applying these changes to the engine's behavior would be greatly appreciated!

    Thanks!

    Code Snippet since I cannot upload files

    JBEAM FILE etki_engine_ecu_advanced_diesel.jbeam

    {
    "etki_engine_ecu_advanced_diesel": {
    "information":{
    "authors":"BeamNG",
    "name":"Advanced Switchable Diesel ECU",
    "value":800
    },
    "slotType" : "etki_engine_ecu_diesel",

    "variables": [
    ["name", "type", "unit", "category", "default", "min", "max", "title", "description"],
    ["$idleRPMRoughness_adv", "range", " ", "ECU Tuning", 5, 0, 3000, "Idle Roughness (EVRY Profile)", "Set Idle Roughness for EVRY Profile"{"stepDis":5}],
    ["$particulates_adv", "range", " ", "ECU Tuning", 1, 0, 10, "Particulates (EVRY Profile)", "Set Afterfire for EVRY Profile"{"stepDis":0.01}]
    ],

    "mainEngine":{
    "torque": [
    ["rpm", "torque"],
    ["$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 0 or nil", "$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 0 or nil"],
    ["$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 500 or nil", "$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 93 or nil"],
    ["$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 1000 or nil", "$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 133 or nil"],
    ["$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 1500 or nil", "$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 168 or nil"],
    ["$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 2200 or nil", "$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 191 or nil"],
    ["$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 2500 or nil", "$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 194 or nil"],
    ["$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 3000 or nil", "$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 195 or nil"],
    ["$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 3500 or nil", "$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 192 or nil"],
    ["$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 4000 or nil", "$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 171 or nil"],
    ["$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 4600 or nil", "$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 158 or nil"],
    ["$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 4800 or nil", "$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 148 or nil"],
    ["$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 5000 or nil", "$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 105 or nil"]
    ],

    "$+idleRPM": "$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 200 or 0",
    "idleRPMRoughness": "$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and $idleRPMRoughness_adv or 0",
    "$+particulates": "$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and $particulates_adv or 0",

    "burnEfficiency": [
    ["$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 0 or nil", "$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 0.10 or nil"],
    ["$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 0.05 or nil", "$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 0.16 or nil"],
    ["$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 0.4 or nil", "$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 0.19 or nil"],
    ["$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 0.7 or nil", "$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 0.24 or nil"],
    ["$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 1 or nil", "$=(not (electrics and electrics.values and electrics.values.ecu_profile == 2)) and 0.22 or nil"]
    ],

    "revLimiterRPM": 5000,
    "revLimiterType":"rpmDrop"
    }
    }
    }


    LUA FILE etkECUProfileController.lua

    local M = {}

    local function setECUProfile(profileID)
    if not electrics then
    log("E", "etkECUProfileController", "Electrics system not found!")
    return
    end
    if not electrics.values then
    electrics.values = {}
    log("W", "etkECUProfileController", "Electrics.values table created.")
    end

    electrics.values.ecu_profile = profileID
    log("D", "etkECUProfileController", "ecu_profile set to: " .. tostring(profileID))

    if scenetree and scenetree.gameplay_display then
    scenetree.gameplay_display.addNotification("ECU Profile set to: " .. tostring(profileID), 3)
    end
    end

    function M.setProfileEVRY()
    log("D", "etkECUProfileController", "Attempting to set EVRY Profile (1)")
    setECUProfile(1)
    end

    function M.setProfileStandard()
    log("D", "etkECUProfileController", "Attempting to set Standard Profile (2)")
    setECUProfile(2)
    end

    function M.getCurrentProfile()
    if electrics and electrics.values then
    return electrics.values.ecu_profile
    end
    return "Electrics not ready or profile not set"
    end

    function M.onInit()
    log("I", "etkECUProfileController", "ETK ECU Profile Controller Initialized.")
    end

    function M.onReset()
    end

    return M
     
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice