This document describes the tested Scheiber CAN integration for a Victron Cerbo GX using a DSD TECH SH-C30A USB-CAN adapter (gs_usb). The passive analyzer elsewhere in the repository remains read-only; the optional Cerbo bridge can transmit only the two generator commands that were live-validated on this installation.
Tested environment:
Victron Cerbo GX
Venus OS v3.75 (20260624163305 v3.75)
Linux 6.12.90-venus-2, armv7l
DSD TECH SH-C30A via gs_usb
Scheiber CAN can2 @ 250000 bit/s
29-bit extended CAN identifiers
Canonical runtime source:
cerbo/bridge.py
version 5.10.2
SHA-256 83b555c1ed77cf60bf38b441e3e04c088d1c6ae74089a4f99b638492782908d4
The bridge publishes:
com.victronenergy.genset.scheiber
com.victronenergy.grid.scheiber_shore
com.victronenergy.acsystem.scheiber_house
com.victronenergy.inverter.scheiber_mastervolt
Victron dbus-generator creates the normal connected-genset manager, typically:
com.victronenergy.generator.startstop1
The bridge also publishes three native Victron tank services, native MasterVolt 2000W Inverter and Shore Power services, native switch outputs (com.victronenergy.switch.scheiber), and, when the GX system battery is explicitly selected, six house-battery services plus two experimental engine-battery services and the generator starter battery.
The following generator commands were tested live on this installation:
02460B88#01 START
02460B88#02 STOP
The bridge sends each accepted command once and deliberately does not implement automatic CAN retries.
The bridge does not transmit AC/House source-selector requests. In particular, it never sends:
0x02420B90
0x02420B88
Those IDs are documented only for protocol analysis. Live validation on one vessel is not an OEM protocol guarantee; preserve the existing generator and marine-electrical safety systems.
Scheiber six-pin connector to SH-C30A:
| Scheiber pin | Function | SH-C30A |
|---|---|---|
| 5 | CAN-H | CAN_H |
| 6 | CAN-L | CAN_L |
| 2 or installation-specific 3 | GND | GND |
| 1 | Recovery | leave open |
| 4 | +12 V | never connect to SH-C30A |
The SH-C30A is USB powered. On an existing correctly terminated Scheiber bus, leave its 120-ohm termination OFF. With vessel power off, approximately 60 ohms between CAN-H and CAN-L normally indicates two 120-ohm end terminators.
The tested Venus image already provided the required runtime tools:
python3
dbus
Victron velib_python / vedbus.py
ip
candump
cansend
svc
Confirm the USB-CAN interface before installation:
lsusb
lsmod | grep -E 'gs_usb|can'
ip -details link showThe tested adapter enumerated as can2.
The bridge refuses to register its extra com.victronenergy.battery.* services while the GX system-battery selection is default. This prevents a Scheiber per-battery service from displacing the existing SmartShunt as the system battery.
Check:
dbus -y com.victronenergy.settings \
/Settings/SystemSetup/BatteryService GetValueIf it returns default, select the existing SmartShunt/system battery explicitly in Venus OS, then restart the bridge. Generator and tank integration do not depend on the additional battery services.
For the tested installation:
AC input 1 = Shore power
AC input 2 = Generator
Observed settings:
/Settings/SystemSetup/AcInput1 = 3
/Settings/SystemSetup/AcInput2 = 2
The bridge reads these settings for diagnostics only and does not rewrite them.
After the relevant changes are merged to main:
mkdir -p /data/scheiber-gx-installer
cd /data/scheiber-gx-installer
wget -O install.sh \
https://raw.githubusercontent.com/danielkope/scheiber-can-analysis-nmea2000/main/cerbo/install.sh
chmod +x install.sh
CAN_IF=can2 CAN_BITRATE=250000 ./install.shTo test an open branch before merge:
BRANCH=fix/tank-dbus-units
BASE="https://raw.githubusercontent.com/danielkope/scheiber-can-analysis-nmea2000/$BRANCH/cerbo"
wget -O install.sh "$BASE/install.sh"
chmod +x install.sh
RAW_BASE="$BASE" CAN_IF=can2 CAN_BITRATE=250000 ./install.shThe installer performs this sequence:
- downloads the complete canonical
cerbo/bridge.pyto a temporary path; - compiles it with
python3 -m py_compile; - verifies its pinned SHA-256;
- downloads the runit
service/runwrapper; - backs up the currently installed script as
/data/scheiber-gx/bridge.py.previous; - replaces
/data/scheiber-gx/bridge.pywith the complete verified script; - installs the runit wrapper;
- persists
/service/scheiber-gx -> /data/scheiber-gx/servicethrough/data/rc.local; - restarts the service with
svc.
A failed download, compile, or checksum happens before the installed bridge is replaced.
cd /path/to/scheiber-can-analysis-nmea2000
CAN_IF=can2 CAN_BITRATE=250000 ./cerbo/install.shWhen local cerbo/bridge.py and cerbo/service/run exist, the installer uses those files directly.
/data/scheiber-gx/bridge.py
/data/scheiber-gx/bridge.py.previous
/data/scheiber-gx/service/run
/data/scheiber-gx/bridge.log
/data/scheiber-gx/status.json
/service/scheiber-gx -> /data/scheiber-gx/service
The persistent runtime files live under /data.
ip -details -statistics link show can2Expected essentials:
- bitrate
250000; - interface
UP; - no rapidly increasing RX/TX errors;
- no repeated bus-off events.
Passive traffic check:
candump -L can2tail -n 100 /data/scheiber-gx/bridge.log
cat /data/scheiber-gx/status.json
sha256sum /data/scheiber-gx/bridge.pyExpected installed SHA for bridge 5.4.2:
6c25ce4b095385217564fc6bf6fdc843dfefd835993d643843811e7f0f737097
Useful service commands:
svc -d /service/scheiber-gx # stop
svc -u /service/scheiber-gx # start
svc -t /service/scheiber-gx # restartUse svc; sv was not installed on the tested image.
for p in ProductName Connected RemoteStartModeEnabled Start StatusCode; do
printf '%-28s ' "$p:"
dbus -y com.victronenergy.genset.scheiber /$p GetValue
doneTypical healthy stopped state:
ProductName: 'Scheiber Generator'
Connected: 1
RemoteStartModeEnabled: 1
Start: 0
StatusCode: 0
Confirm Victron matched the genset:
for p in Enabled GensetService GensetServiceType GensetInstance \
State ManualStart ManualStartTimer RunningByCondition \
RunningByConditionCode Runtime; do
printf '%-28s ' "$p:"
dbus -y com.victronenergy.generator.startstop1 /$p GetValue
doneGensetService should be com.victronenergy.genset.scheiber and Enabled should be 1.
The ownership rule is fundamental:
com.victronenergy.genset.scheiber /Startis Victron command state;- Scheiber CAN feedback never writes
/Startlocally; /StatusCodeis physical generator feedback;- a physical/external Scheiber START is adopted into Victron by setting manager
/ManualStart=1; - when Victron then synchronizes
/Start=1, the bridge suppresses duplicate CAN START; - a physical STOP clears
/ManualStartonly when manual ownership is active; - automatic Victron start conditions are not silently disabled.
Victron status mapping:
| Physical state | /StatusCode |
|---|---|
| stopped / idle | 0 |
| STARTING | 1 |
| RUNNING / RUNNING_SETTLED | 8 |
| STOPPING | 9 |
| Payload | Meaning | Status |
|---|---|---|
01 |
START | live transmit confirmed |
02 |
STOP | live transmit confirmed |
Direct low-level diagnostics only:
cansend can2 02460B88#01
cansend can2 02460B88#02Normal operation should use the Victron generator UI or D-Bus manager.
| Payload | Interpretation |
|---|---|
00 |
OFF_IDLE |
01 |
RUNNING_SETTLED |
02, 03 |
STARTING |
04, 05 |
STOPPING |
06, 07 |
abort/error candidates; unresolved |
Bytes 0-1 are uint16 little-endian x0.1 Hz:
F4 01 -> 500 -> 50.0 Hz
90 01 -> 400 -> 40.0 Hz
00 00 -> 0.0 Hz
Live testing established that this signal is generator-specific. With the generator off and shore power present, 0x005A1020 remained 0 Hz while shared 0x02040898 still reported approximately 235 V / 50 Hz.
The bridge requires 47-53 Hz plus a 3 s confirmation hold before declaring RUNNING. A 0 Hz generator-specific sample confirms physical STOPPED.
Scheiber has two useful stopped milestones:
005A1020 = 0.0 Hz-> physical frequency stopped (STOPPED);02440B88#00-> controller shutdown settling complete (OFF_IDLE).
On the tested installation, OFF_IDLE can arrive roughly one minute after the engine reaches 0 Hz. A START sent during that interval was transmitted but ignored by Scheiber. Starting again after OFF_IDLE succeeded.
Bridge 5.4.2 does not queue an early START. Wait for OFF_IDLE before requesting a new start.
Timed runs are manager-owned and were proven end-to-end:
/ManualStart = 1
/ManualStartTimer > 0
/RunningByCondition = 'manual'
/RunningByConditionCode = 1
/ManualStartTimer counts down while /Runtime counts up. At expiry, Victron writes /Start=0; the bridge sends exactly one 02460B88#02; Scheiber shutdown feedback updates /StatusCode.
Current gui-v2 may show the timed-run icon without exposing the older live +/- duration controls. That is a Victron UI behavior; the timer backend remains native and writable. No gui-v2 patch is included here.
When manually writing /ManualStartTimer, use an integer variant. With Victron's dbus utility, %12000 is an integer; plain 12000 may become a string. A string timer can crash dbus-generator when it performs integer arithmetic. Prefer the Victron UI.
The bridge protects a running generator if dbus-generator/startstop1 disappears and is recreated. Without this guard, a replacement manager initializes /Start=0, which can look like a real STOP.
The bridge:
- caches
/ManualStart,/ManualStartTimer, running condition, and state; - enters a 30 s recovery guard while the physical genset is STARTING/RUNNING;
- suppresses the replacement manager's initialization
/Start=0from CAN; - restores a numeric timed-run value and manual ownership where applicable;
- suppresses the duplicate synchronized
/Start=1transmission.
Look for MANAGER RECOVERY in bridge.log when validating this path.
Receive-only mappings:
| CAN ID | Meaning |
|---|---|
0x02400B90 |
AC panel applied source |
0x02400B88 |
House panel applied source |
0x02140898 |
Shared AC ramp transition marker (0x02 down, 0x03 up); not an inverter enable-state signal |
0x02040B90 bytes 4-5 BE |
AC panel voltage |
0x02040B88 bytes 4-5 BE |
House panel voltage |
Source enum:
01 = OFF
02 = SHORE
04 = GENERATOR
08 = INVERTER (Effective House source when Mastervolt is active)
Inverter & AC D-Bus paths on com.victronenergy.genset.scheiber:
/Scheiber/HousePanelAppliedSource&/Scheiber/HousePanelAppliedSourceText/Scheiber/AcPanelAppliedSource&/Scheiber/AcPanelAppliedSourceText/Scheiber/MastervoltInverterState&/Scheiber/MastervoltInverterStateText/Scheiber/MastervoltSupplyingHouse&/Scheiber/MastervoltSupplyingHouseText/Scheiber/HousePanelVoltage&/Scheiber/AcPanelVoltage/Scheiber/HousePanelFrequencyStatus&/Scheiber/AcPanelFrequencyStatus
Node-RED flow cerbo/node-red-ac-power-flow.json provides real-time power routing matrix monitoring.
The receive-only com.victronenergy.acsystem.scheiber_house service maps the
House selector to the native GUI-v2 two-input model: input 1 is Shore (Victron
type 3), input 2 is Generator (type 2), and /Ac/ActiveIn/ActiveInput follows
confirmed 0x02400B88 feedback. It also publishes the active House-bus voltage.
The guarded GUI-v2 patch replaces generic AC input 2/Passthru presentation
with Generator/Shore, a vessel-specific Generator feeding House bus state,
and the selected input's voltage. The Generator Overview card reads /StatusCode
and /Ac/L1/Voltage, displaying values such as Running · 230 V.
The separate A/C selector remains available on /Scheiber/AcPanel*; stock
Overview supports one system-level selector and therefore cannot draw both
physical transfer panels independently.
Confirmed frame 0x02040580 contains big-endian uint16 percentages:
| Bytes | Tank | Vessel capacity |
|---|---|---|
| 0-1 | Fresh water | 600 L |
| 2-3 | Diesel tank 1 | 500 L |
| 4-5 | Diesel tank 2 | 500 L |
Published services:
com.victronenergy.tank.scheiber_fresh
com.victronenergy.tank.scheiber_diesel1
com.victronenergy.tank.scheiber_diesel2
The configuration remains in litres for human readability, but Victron D-Bus volume paths use cubic metres:
/Level percent
/Capacity m3
/Remaining m3
Therefore:
600 L -> /Capacity 0.600
500 L -> /Capacity 0.500
For example, 74% of a 600 L fresh-water tank is:
/Level 74.0
/Capacity 0.600
/Remaining 0.444
Verify all three after installation:
for s in \
com.victronenergy.tank.scheiber_fresh \
com.victronenergy.tank.scheiber_diesel1 \
com.victronenergy.tank.scheiber_diesel2
do
echo "===== $s ====="
for p in Level Capacity Remaining FluidType CustomName; do
printf '%-12s ' "$p:"
dbus -y "$s" "/$p" GetValue
done
doneThe tank service text formatter converts m3 back to litres for human-readable display. Signal K receives the correct SI values directly from D-Bus.
06020580 06060580 060A0580 060E0580 06120580 06160580
Per frame:
| Bytes | Decode | Confidence |
|---|---|---|
| 0-1 | LE16 x0.01 V | confirmed |
| 2-3 | (LE16 - 0x4E00) * 0.1 A |
sign/offset strong; scale candidate |
| 4-5 | LE16 x1 % SoC | confirmed for this installation |
| Channel | CAN ID | Source | Decode | D-Bus Service |
|---|---|---|---|---|
| Starboard Engine Starter | 0x00501008 |
60A Multi-Output Charger (B1) | LE16[0..1] * 0.1 V |
com.victronenergy.battery.scheiber_engine_starboard |
| Port Engine Starter | 0x00561008 |
60A Multi-Output Charger (B3) | LE16[2..3] * 0.1 V |
com.victronenergy.battery.scheiber_engine_port |
| Generator Starter | 0x00501020 |
25A Generator Charger Family | LE16[0..1] * 0.1 V |
com.victronenergy.battery.scheiber_generator_startercom.victronenergy.genset.scheiber (/StarterVoltage) |
Note
Generator Starter Dual-Publication Design: The generator starter battery voltage is deliberately published to two locations on D-Bus:
com.victronenergy.genset.scheiber(/StarterVoltage): Standard Victron generator property displayed directly within the Generator tile and settings menu for generator-specific crank monitoring.com.victronenergy.battery.scheiber_generator_starter(DeviceInstance 88): Standalone battery service ensuring the starter battery is also visible in the unified Device List → Batteries menu alongside the Port and Starboard engine batteries.
To avoid false alarms during normal engine/generator cranking dips (where voltage pulls down to ~10.5V for 1-3 seconds), a smart filtering engine is evaluated in cerbo/bridge.py:
Voltage Normal (> 12.5V) ──────────────────────────► Alarm State: 0 (OK)
│
▼ (<= 12.2V sustained >= 15.0s)
Voltage Warning (<= 12.2V) ────────────────────────► Alarm State: 1 (Warning)
│
▼ (<= 11.8V sustained >= 15.0s)
Critical Low Voltage (<= 11.8V) ───────────────────► Alarm State: 2 (Alarm)
│
▲ (Voltage recovers >= 12.1V / 12.5V via 0.3V hysteresis)
- Transient Cranking Rejection: Any transient voltage dip lasting
< 15.0 secondsis completely ignored. - Hysteresis Recovery: Warnings require voltage to rise back to
>= 12.5 V(threshold + 0.3V) to clear, preventing alarm oscillations. - Published D-Bus Paths:
/Alarms/LowVoltageon all battery services (0= OK,1= Warning,2= Alarm)./StarterVoltageAlarm&/Alarms/StarterVoltageoncom.victronenergy.genset.scheiber.
Displays live AC sources (Grid/Shore vs Generator vs MasterVolt Inverter) and DC battery bank flow:
Independent monitoring for MasterVolt 2000W Inverter (Scheiber CAN) and Starlink Phoenix Inverter (VE.Direct):
Standard SI cubic-metre conversion mapped directly to GUI level bars:
Native switch outputs and battery monitoring tiles rendered in GUI-v2:
The installer backs up the previous runtime script before replacement:
/data/scheiber-gx/bridge.py.previous
Manual rollback:
svc -d /service/scheiber-gx
cp /data/scheiber-gx/bridge.py.previous /data/scheiber-gx/bridge.py
chmod 755 /data/scheiber-gx/bridge.py
python3 -m py_compile /data/scheiber-gx/bridge.py
svc -u /service/scheiber-gxTo disable the integration while retaining files:
./cerbo/uninstall.shFor a labelled passive capture:
mkdir -p /data/scheiber-captures
OUT=/data/scheiber-captures/capture-$(date +%Y%m%d-%H%M%S).log
candump -L can2 > "$OUT"Do not use broad CAN replay as a diagnostic technique on the live vessel bus.



