Controlling Orion XS charging current based on engine RPM via vehicle CAN bus

Hi all, this is my first post here – hope it’s useful to someone.

Disclaimer: This is a DIY project for people who know what they are doing. Working with a vehicle CAN bus carries real risks – you can cause malfunctions or damage. Do this at your own risk.

Goal

The idea is to dynamically limit the Orion XS maximum charging current based on engine RPM read from the vehicle CAN bus. This allows the charger to back off when the engine is idling and ramp up only when the alternator is actually producing enough power.

The test vehicle is a Mercedes Sprinter 907.


Hardware

  • Victron Cerbo GX (Venus OS Large)

  • Victron Orion XS – connected to Cerbo via VE.Direct cable

  • Teltonika ECAN02 CAN bus adapter – used as a passive tap on the vehicle CAN network

Why the ECAN02 (or similar isolated adapter)

Older Cerbo GX units do not have galvanically isolated CAN. Connecting directly to the vehicle CAN network without isolation risks injecting noise or unintended frames into a safety-critical bus. The ECAN02 provides galvanic isolation and acts as a passive listener – it does not transmit onto the vehicle bus.


Wiring

Vehicle side – under the driver’s seat (Sprinter 907)

The Sprinter 907 CAN bus is accessible under the driver’s seat. The relevant wires are:

  • Brown – CAN_L

  • Brown/Red – CAN_H

Connect the ECAN02 accordingly. Power the ECAN02 from the same source as the Cerbo GX – this is important for a stable common ground reference.

Alternative power source worth considering: If you are using an Orion XS, you already have a shared ground between the vehicle and the hotel electrical system. In that case, you could power the ECAN02 from terminal 15 (ignition-switched +12V), which is available under the driver’s seat on the Sprinter. This way the adapter only starts transmitting to the Cerbo after the ignition is on, which is a cleaner behaviour. That said, I haven’t verified this approach yet – it needs testing.

Cerbo GX side – VE.Can port

Connect the ECAN02 output to the Cerbo VE.Can RJ45 port. Pin assignment:

  • Pin 7 – CAN_H

  • Pin 8 – CAN_L


Software setup

This assumes you are already running Venus OS Large with Node-RED. Install the SocketCAN palette in Node-RED via Manage palette:

node-red-contrib-socketcan

Note: in this library the node names are counterintuitivesocketcan-out is for receiving frames (has an output), and socketcan-in is for sending frames (has an input). Keep this in mind when building your flow.

3. CAN bus speed

The Sprinter 907 CAN bus runs at 250 kbps, which is also the default speed of the Cerbo GX VE.Can port – so no configuration change is needed on the Cerbo side.

I tested this with nothing else connected to the VE.Can port. I’m not yet sure what happens when the Cerbo is flooded with vehicle CAN frames while other VE.Can devices (like the Orion XS) are also present on the same bus – this needs more testing.


Node-RED flow

The flow reads Engine RPM from the vehicle CAN, decodes it, maps it to a current limit percentage, and sends that to the Orion XS via the Cerbo.

Flow structure

socketcan-out → function (decode + map) → [further control logic]

Function node – decode and map RPM to percent

This example uses the following DBC signal definition from the Sprinter 907:

BO_ 177 Engine_Data: 8 Vector__XXX
 SG_ Engine_RPM : 24|16@1+ (1,0) [0|8000] "rpm" Vector__XXX

Signal is 16-bit unsigned little-endian, starting at bit 24 (byte 3), CAN ID 0xB1 (177 decimal).

// Filter by CAN ID
if (msg.payload.canid !== 0xB1) return null;

const data = msg.payload.data;

// Decode Engine_RPM: bit 24, 16-bit, little-endian unsigned
const rpm = (data[4] << 8) | data[3];

// Map RPM to charging current limit (percent of max)
let percent = 0;
if (rpm >= 2000) {
    percent = 100;
} else if (rpm >= 1500) {
    percent = 60;
} else if (rpm >= 1200) {
    percent = 40;
} else if (rpm >= 800) {
    percent = 20;
} else {
    percent = 0;  // idle or engine off – stop charging
}

msg.payload = { rpm, percent };
return msg;

The RPM thresholds and percentages are a starting point – adjust them to your alternator’s actual output curve.


Current status

This has been tested on a live Sprinter 907 with the exact setup described above – CAN parsing, RPM decoding and percentage mapping all work correctly in Node-RED on Venus OS Large with the ECAN02 connected to VE.Can.

The Orion XS control side (actually sending the current limit from Node-RED to the Orion XS) I have not been able to test as I don’t have an Orion XS available. If you have one in your installation and manage to get this working end-to-end, please share your results in the comments.


Going further – combining RPM with battery voltage

You can extend the logic by also reading the vehicle battery voltage. On the Sprinter 907:

BO_ 290 Battery: 8 Vector__XXX
 SG_ Battery_Voltage : 0|8@1+ (0.1,0) [0|25.5] "V" Vector__XXX

Signal is 8-bit unsigned, starting at bit 0 (byte 0), scale 0.1V, CAN ID 0x122 (290 decimal).

if (msg.payload.canid === 0x122) {
    const voltage = msg.payload.data[0] * 0.1;
    flow.set('battVoltage', voltage);
    return null;
}

A voltage above ~14V typically means the smart alternator is actively charging – which on some vehicles also indicates regenerative braking or a high-load generation phase. In that situation you could override the RPM-based limit and go straight to 100%:

const battVoltage = flow.get('battVoltage') || 0;
if (battVoltage > 14.0) {
    percent = 100;  // alternator fully active, safe to draw maximum
}

This is just one example of how combining multiple CAN signals gives you a more intelligent charging strategy than RPM alone. Whether this logic makes sense for your specific vehicle and alternator depends on your setup – treat it as a starting point.


If you try this on your installation, please share your results in the comments.

Neat idea. External alternator regulators such as the Wakespeed WS500 have a linear profile for the current vs rpm rather than a series of steps with rpm. This makes for smoother load changes. It may not be an issue for a vehicle engine where engine power >> alternator power. I know on boats where you can have a 200A alternator on a 40hp engine that at low revs the alternator can take a significant fraction of the engine output, hence the linearisation approach is better. Just an idle thought.