Technical reference for the reverse-engineered REDARC bus. The
RedVision_TVMS_components.dbc file is the
source of truth for signal scaling and confirmation status; this document is the
human-readable companion. For setup and usage, see the README.
Status legend:
CONFIRMED= validated against capture, safe to rely on.PARTLY CONFIRMED= purpose known, some bytes unknown.CANDIDATE/DIAGNOSTIC= exposed for testing, not yet locked in.
The bus is 250 kbit/s CAN using 29-bit extended IDs in a J1939 / RV-C style layout. Every ID is treated as three fields:
29-bit CAN ID = Priority + DGN (message group) + Source Address
(top bits) (PGN-style middle) (low 8 bits)
Example — 0x13F10208:
DGN (group) = 0x1F102 ((id >> 8) & 0x1FFFF)
Source Address = 0x08 (id & 0xFF) -> Battery Sensor
The firmware always keys off the full 29-bit ID, then matches on
(DGN, source address) so it can tell, e.g., the Manager's status from the
display's rebroadcast of the same numbers.
| Addr | Device | Role |
|---|---|---|
0x01 |
Manager30 | Battery manager / charger / solar MPPT |
0x08 |
Battery Sensor | Shunt / BMS (current, voltage, temp, SOC) |
0x20 |
RedVision display 1 | Screen; also the source of most button commands |
0x21 |
RedVision display 2 | Second screen / status |
0x24 |
TVMS1280 | 10 relay outputs + inverter, tanks, temps, voltage inputs |
0x30 |
TVMS Rogue | 10 dimmable outputs, hardware buttons, tanks, input V/A |
0x22 |
This ESP32 bridge | Our own address, used as the source of command/poll frames (configurable) |
0xFA |
Diagnostic / request tool | Readout & history-request traffic |
- Source-node currents are clean 32-bit values centred on 1,000,000:
Current_A = raw / 1000 - 1000(so1,020,000= +20 A,990,000= -10 A). - Display rebroadcast currents are 16-bit, centred on 10,000:
Display_A = raw / 10 - 1000. - Status frames are multiplexed: byte
D1is a page / item index and the remaining bytes mean different things per page (e.g. TVMS12800x1BFD0224carries tanks, temps and voltages on differentD1values). - Commands are short frames sent from a display address to the target
hardware (e.g.
0x0F00FF20from display0x20), withD1selecting the command and later bytes the value.
Everything ships as one ESPHome external component, redarc. A singleton
RedarcCanDispatcher subscribes to the CAN bus once and hands every frame to
each device's listener; a device simply asks "did this frame match my
(DGN, source address)?". No YAML on_frame: automation is needed.
- RTR (remote-request) frames are logged with an
rtr=flag but not decoded. - Decode helpers:
u16_le/u32_le,rvc_dgn/rvc_source_address,rvc_matches, and thecurrent_32_centered/current_display_16_centeredscalers described above.
The Battery and Manager components poll for stored history at a configurable
interval (soc_history_poll_interval / solar_history_poll_interval, default
60 s, 0s disables). Each poll sends an RTR frame — extended ID, DLC 8, no
payload — and the source node answers with its paged history:
| Request (RTR) | Answer | Feeds |
|---|---|---|
0x0FFCD0·· |
0x13FCD008 pages |
SOC Hourly History |
0x0FFCD2·· |
0x13FCD208 pages |
SOC daily low → Daily Range History |
0x0FFCD4·· |
0x13FCD408 pages |
SOC daily high → Daily Range History |
0x0FFCD6·· |
0x03FCD601 pages |
Solar Energy + Solar Day 1-12 History |
The ·· low byte is our host_address. The raw replies (and the RTR requests,
tagged rtr=1) appear in the DEBUG CAN log, so this doubles as a way to
re-fetch history on demand without opening the physical screen.
Presence discovery is passive. Every device transmits a 0x1F404 identity
frame roughly once per second on its own, so the bus can be enumerated just by
listening — no request needed (it works in LISTENONLY). The firmware's
handle_device_identity_() keys on DGN 0x1F404; D1-D4 are the serial prefix
(LE), D5-D6 the serial suffix (LE), and D7 the device-type code:
0x1F404 frame |
Source | Type (D7) |
|---|---|---|
0x03F40401 |
Manager30 | 0x01 |
0x1BF40408 |
Battery Sensor | 0x03 |
0x1BF40420 |
RedVision Display 1 | 0x0C |
0x1BF40421 |
RedVision Display 2 | 0x0C |
0x1BF40424 |
TVMS1280 | 0x0E |
0x1BF40430 |
TVMS Rogue | 0x16 |
Directed info requests. After discovery, the diagnostic tool reads device
metadata with a directed PGN request 0x0F03<dest>FA (dest = target source
address, requester 0xFA). Payload D1-D2 is the requested DGN, little-endian
(05 F4 → 0x1F405). These are device info, not presence:
| Requested DGN | Purpose | Response notes |
|---|---|---|
0x1F405 |
Unique identifier | e.g. 1BF40524 |
0x1F400 |
Firmware / hardware version | — |
0x1F402 |
Manufacturing / build date | — |
0x1F403 |
Product name | segmented ASCII: D1 = segment index, D2-D8 = chars (FF pad), e.g. reassembles to RedVision Display |
TVMS configuration groups (requested the same way once a TVMS is identified):
| Requested DGN | Observed content |
|---|---|
0x1FD04 |
Channel / output names (e.g. Starlink, Pump, Inverter, Master switch) |
0x1FD06 |
Channel configuration data |
0x1FD0A |
Channel option / state flags |
0x1FD0C / 0x1FD0E / 0x1FD10 |
Additional configuration |
Block-transfer transport (for larger config dumps): a request 0x0E86<dest>FA
makes the device stream data frames on 0x0281FA<sa>, ending each block with
0x0284FA<sa> (block length / checksum / completion). Used per device:
0E8620FA→0281FA20/0284FA20, and likewise for 0x21/0x24/0x30.
For ESPHome, listening for
0x1F404is the presence mechanism; everything above it is device-info / configuration discovery.
TVMS1280 output : 0x0F002420 CB 00 FF <ch> <00|01> 00 00 00 (ch 0x04..0x0E)
Rogue on/off : 0x0F003020 CB 00 FF <ch> <00|01> 00 00 00 (ch 0x0C..0x15)
Rogue dim : 0x0F053020 <ch> 01 <dir> 05 00 FF FF FF (dir 01=down,64=up,FF=release)
Charging mode : 0x0F00FF20 43 00 FF FF <00|01> 00 00 00 (00=Touring,01=Storage)
TVMS1280 out fb : 0x1BFD0024 <base> <s0..s6> (00=off,01=on,06=fuse-blown,0A=over-temp,14/15=off/on-override,F8=unconfigured,FF=ignore)
Rogue level fb : 0x1BFD1230 <base> <l0..l6> (% per channel)
Rogue buttons : 0x1BFD0030 <base> <b1..b7> (00=inactive,01=active; D1=0x08 D2 = button 8)
| Device | CAN ID | DGN | MUX | Signal | Bytes | Decode | Status |
|---|---|---|---|---|---|---|---|
Manager30 0x01 |
0x03F20A01 |
0x1F20A |
— | Output Current A | D1-D4 | raw/1000−1000 | CONFIRMED |
Manager30 0x01 |
0x03F20A01 |
0x1F20A |
— | Battery Voltage | D5-D6 | raw×0.001 V | CONFIRMED |
Manager30 0x01 |
0x03F20401 |
0x1F204 |
— | AC Input Current A | D1-D4 | raw/1000−1000 (LE) | CONFIRMED |
Manager30 0x01 |
0x03F20401 |
0x1F204 |
— | AC Input Voltage | D5-D6 | raw V (LE) | CONFIRMED |
Manager30 0x01 |
0x03F20401 |
0x1F204 |
— | DC Input Voltage Raw | D7-D8 | signed raw | UNCONFIRMED |
Manager30 0x01 |
0x03F20801 |
0x1F208 |
— | Solar Current A | D1-D4 | raw/1000−1000 | CONFIRMED (verify DBC export) |
Manager30 0x01 |
0x03F20801 |
0x1F208 |
— | Solar Voltage | D5-D6 | raw×0.001 V | CONFIRMED |
Manager30 0x01 |
0x03F20801 |
0x1F208 |
— | Solar Power W | derived | I × V | DERIVED |
Manager30 0x01 |
0x03FCD601 |
0x1FCD6 |
D1 page | Solar Energy Wh (per-day buckets) | D2-D7 | 16-bit LE Wh per day slot | CONFIRMED |
Manager30 0x01 |
0x03F10801 |
0x1F108 |
— | Charging Mode | D1 bit0 | 0=Touring,1=Storage (preferred mode source) | CONFIRMED |
Manager30 0x01 |
0x03F20001 |
0x1F200 |
— | Charging Stage + Mode | D1 | stage = D1 & 0xFE: 0x00 Not Charging, 0x10 Desulphation, 0x20 Soft-start, 0x30 Boost, 0x40 Absorption, 0x50 Battery Test, 0x60 Equalize, 0x70 Float, 0x80 Maintenance. D1 bit0 = mode (0=Touring, 1=Storage), used as a fallback when 0x1F108 has not been seen |
CONFIRMED |
Manager30 0x01 |
0x03F20601 |
0x1F206 |
— | Vehicle Input Current A | D1-D4 | raw/1000−1000 | CONFIRMED |
Manager30 0x01 |
0x03F20601 |
0x1F206 |
— | Vehicle Input Voltage | D5-D6 | raw×0.001 V | CONFIRMED |
Manager30 0x01 |
0x03F20601 |
0x1F206 |
— | Vehicle Input Trigger | D8 | 0 Auto, 1 12V, 2 24V, 3 Ignition, 5 On | CONFIRMED |
Battery 0x08 |
0x13F10208 |
0x1F102 |
— | Current A | D1-D4 | raw/1000−1000 | CONFIRMED |
Battery 0x08 |
0x13F10208 |
0x1F102 |
— | Voltage | D5-D6 | raw×0.001 V | CONFIRMED |
Battery 0x08 |
0x13F10208 |
0x1F102 |
— | Temperature | D7 | raw−60 | CONFIRMED |
Battery 0x08 |
0x13F10408 |
0x1F104 |
— | SOC % | D1 | raw % | CONFIRMED |
RedVision 0x20 |
0x13F28020 |
0x1F280 |
— | Battery Current Display A | D1-D2 | raw/10−1000 | CONFIRMED |
RedVision 0x20 |
0x13F28020 |
0x1F280 |
— | Device Current Display A | D5-D6 | raw/10−1000 | CONFIRMED |
RedVision 0x21 |
0x13F28221 |
0x1F282 |
— | Manager Output Current Display A | D7-D8 | raw/10−1000 | CONFIRMED |
| RedVision disp | 0x13F28220 |
0x1F282 |
— | Vehicle Current Display A | D3-D4 | raw/10−1000 | CONFIRMED |
| RedVision disp | 0x13F28420 |
0x1F284 |
— | Vehicle Voltage Display | D3-D4 | raw×0.1 V | CONFIRMED |
TVMS Rogue 0x30 |
0x1BFD0230 |
0x1FD02 |
D1=0x09 |
Water Tank 1 % | D2 | raw % | CONFIRMED |
TVMS Rogue 0x30 |
0x1BFD0230 |
0x1FD02 |
D1=0x09 |
Water Tank 2 % | D3 | raw % | CONFIRMED |
TVMS Rogue 0x30 |
0x1BFD1230 |
0x1FD12 |
D1 base | Output Level +0..6 | D2-D8 | raw % | CONFIRMED |
TVMS Rogue 0x30 |
0x1BFD0030 |
0x1FD00 |
D1 base | Input Button 1..8 | D2-D8 | 0=inactive,1=active | CONFIRMED |
TVMS Rogue 0x30 |
0x1BFD1430 |
0x1FD14 |
D1 base | Output Dim Activity +0..6 | D2-D8 | activity only, not input state | CONFIRMED |
TVMS Rogue 0x30 |
0x1BFD0230 |
0x1FD02 |
D1=0x16 |
Input Voltage | D2-D3 | uint16 LE × 0.001 V | CONFIRMED |
TVMS Rogue 0x30 |
0x1BFD0230 |
0x1FD02 |
D1=0x16 |
Input Current | D4-D5 | uint16 LE × 0.001 A | CONFIRMED |
TVMS1280 0x24 |
0x1BFD0024 |
0x1FD00 |
D1 base | Output Status +0..6 | D2-D8 | 00=off,01=on,06=fuse-blown,0A=over-temp,14/15=off/on-override,F8=unconfigured,FF=ignore | CONFIRMED |
TVMS1280 0x24 |
0x1BFD0224 |
0x1FD02 |
D1=0x14 |
Temperature 1 °C | D2 | raw−100 | CONFIRMED |
TVMS1280 0x24 |
0x1BFD0224 |
0x1FD02 |
D1=0x11 |
Temperature 2 °C | D6 | raw−100 | CONFIRMED |
TVMS1280 0x24 |
0x1BFD0224 |
0x1FD02 |
D1=0x14 |
Tank 1 % | D4 | raw % | CONFIRMED |
TVMS1280 0x24 |
0x1BFD0224 |
0x1FD02 |
D1=0x14 |
Tank 2 % | D6 | raw % | CONFIRMED |
TVMS1280 0x24 |
0x1BFD0224 |
0x1FD02 |
D1=0x17 |
Tank 3 % | D2 | raw % | CONFIRMED |
TVMS1280 0x24 |
0x1BFD0224 |
0x1FD02 |
D1=0x17 |
Tank 4 % | D4 | raw % | CONFIRMED |
TVMS1280 0x24 |
0x1BFD0224 |
0x1FD02 |
D1=0x17 |
Tank 5 % | D6 | raw % | CONFIRMED |
TVMS1280 0x24 |
0x1BFD0224 |
0x1FD02 |
D1=0x1A |
Tank 6 % | D2 | raw % | CONFIRMED |
TVMS1280 0x24 |
0x1BFD0224 |
0x1FD02 |
D1=0x11 |
Voltage Input 1 | D2-D3 | uint16 LE mV/1000 | CONFIRMED (item 0x11) |
TVMS1280 0x24 |
0x1BFD0224 |
0x1FD02 |
D1=0x11 |
Voltage Input 2 | D4-D5 | uint16 LE mV/1000 | CONFIRMED (item 0x12) |
TVMS1280 0x24 |
0x1BFD0024 |
0x1FD00 |
D1 base | Digital Inputs 1–3 | ch 0x01-0x03 |
0=off,1=on | CANDIDATE |
Solar Energy note: the DBC also documents a single 32-bit
Solar_Energy_WhonD2-D5of page0x00. That is a low-value special case; the firmware uses the per-day 16-bit bucket layout —D1is the page index andD2-D7are three days' Wh, so 4 pages cover 12 days (page 0 = today/−1/−2 … page 3 = −9/−10/−11). It sums all known buckets into Solar Energy and publishes the per-day values to the history text sensor. The pages are requested with an RTR frame to0x0FFCD6··(··= ourhost_address); the Manager answers on0x03FCD601.