Documentation about Huawei R48xx 48V power supplies
Loading README and project media…
Documentation about Huawei 48V power supplies
psu.scad)Should also fit R4830G2, R4850G2 and R4850N2 as these are all 40.8x105x281mm.
Is modeled with a bit of clearance so it can be used as a negative directly and fit when 3D printed.

connectors/PHZ-F020304-BW001/huawei-r4850g-connector.scad)Might also be compatible with other connector manufacturers if they have the same dimensions.
Is modeled without clearance so it should be expanded a bit to use as a negative.
Fits the PSU card-edge when positioned at the bottom back of the PSU extrusion/profile (translate([0,-frontDepth - profileLength,-profileHeight/2])).

psu-case.scad)Parts to mount a Huawei R4830S1 PSU and PHZ-F020304-BW001 connector to a plate/board.
Mounts to the board using 4mm countersink screws, the connector is mounted to the part with M3 screws.
The PSU can slide in from the front and is held in place using the original metal handle/clip on the front of the PSU.
Also on Printables.
(Photo is of an old version with less space for the screwdriver and with steeper angles which was more fragile)
There seem to be a handful of connectors that are compatible with these power supplies. I have not yet done an exact comparison between the different connectors / PSU card edges, but likely some of these connectors and card edges are cross-compatible with each other as they look at least similar.
Fits at least R4850G2
My R4830S1 came with one, so it does definitely fit that.
looking at the connector at the back of the PSU, the connections (left to right are):
The PSU output capacitors are large. If you connect the unpowered PSU up to a battery, there will be sparks. To avoid this, the PSU should either be on already or a pre-charge resistor (possibly the internal one?) should be used.
The PSU's internal fan control method uses the input/ambient temperature to determine the fan speed.
This means, even when under heavy load, the fan speed increases only marginally because the
internal/PCB temperature doesn't really affect the input/ambient temperature sensor.
This lets the PSU run really hot (>80°C at full load).
There are CAN commands to set the fan mode (auto / full speed) and to set the fan duty cycle (0-100%).
If running at anywhere near full power (>50% maybe) the fan speed should either be set to 100% or temperature
controlled via the duty cycle (if noise matters).
If you just want to control the PSU without implementing all the commands yourself, you can use my fork of an existing ESPHome integration (either directly or as a reference implementation): patagonaa/esphome-huawei-r4850
The CAN protocol is almost the same between all PSUs of the R48xx-series and apparently (with other protocol IDs)
is also used in other PSUs (like the R100030G with 1000V 30A, used for EV charging, for which there are docs in /docs)
and possibly even different power electronics products (there are hints pointing at the C28005G1 48V to 280V 5A
DC-DC converter and MPPT solar chargers).
This documentation is a summary of own tests, documentation of other products and a bunch of other peoples'
implementations and documentation (see Sources).
Thus, this is incomplete and possibly not 100% correct. I did, however test and verify almost all of the things
documented here, with an R4830S1, R4850G2 and R4850G6, so I'm reasonably sure it is correct.
The CAN interface uses 125kbps rate with extended 29-bit identifiers.
The CAN message IDs do not specify a single value/register. Instead, the message ID is used to encode the prococol, PSU address, command, message direction, etc.
Example: 1081407F
Interpretation:
Bits: 000a aaaa abbb bbbb cccc cccc deee eefg
20 or 21 - looks like 20 is used for communication between PSUs, 21 is used for communication between controller and PSU)1F)Apparently the PSU can have a "hardware address" and "software address" but even the original "SMU02B" controller ("Site Monitoring Unit") seems to use only the software address.
The "software address" is negotiated automatically if multiple PSUs are on one CAN bus (see Software address negotiation).
I couldn't get any PSUs to respond to the "hardware address" so far. Looking at the docs, it seems like this address has to be set via CAN and is saved in the PSU.
The "software address" is negotiated between the PSUs whenever a PSU powers up.
The addresses start at 1 and the order is determined by the order of serial numbers (lowest serial = addr 1, second lowest = addr 2, etc.).
This serial number is the same as can be read from register 002 of the 50 info response.
The negotiation flow is as follows:
30 01 and its serial number to the CAN ID 0x1000107E 3 times ~130ms apart.30 02 and its serial number with the CAN ID 0x10xx107E (where xx is its current soft address) ~8 times (exact number is insignificant) ~350ms apart.Example:
1001117E: 00 01 00 00 00 00 00 00 <-- messages from address 1 (PSU 1, serial 64 46 ...)
1001117E: 00 01 00 00 00 00 00 00
1001117E: 00 01 00 00 00 00 00 00
--- PSU 2 (serial 24 68 ...) plugged in here ---
1000107E: 30 01 24 68 23 8C 3C 2F <-- PSU 2 (serial 24 68 ...) requests renegotiation (3 times)
1000107E: 30 01 24 68 23 8C 3C 2F
1001107E: 30 02 64 46 85 50 02 AF <-- PSU 1 sends its serial number 9 times
1000107E: 30 01 24 68 23 8C 3C 2F
1001107E: 30 02 64 46 85 50 02 AF
1001107E: 30 02 24 68 23 8C 3C 2F <-- PSU 2 sends its serial number 8 times
1001107E: 30 02 64 46 85 50 02 AF
1001107E: 30 02 24 68 23 8C 3C 2F
1001107E: 30 02 64 46 85 50 02 AF
1001107E: 30 02 24 68 23 8C 3C 2F
1001107E: 30 02 64 46 85 50 02 AF
1001107E: 30 02 24 68 23 8C 3C 2F
1001107E: 30 02 64 46 85 50 02 AF
1001107E: 30 02 24 68 23 8C 3C 2F
1001107E: 30 02 64 46 85 50 02 AF
1001107E: 30 02 24 68 23 8C 3C 2F
1001107E: 30 02 64 46 85 50 02 AF
1001107E: 30 02 24 68 23 8C 3C 2F
1001107E: 30 02 64 46 85 50 02 AF
1001107E: 30 02 24 68 23 8C 3C 2F
--- Both PSUs stop sending their serial numbers ---
--- ~3 second gap ---
--- Both PSUs start sending messages again with their new software address determined by the serial number sort order ---
1001117E: 00 01 00 01 00 00 00 00 <-- message from PSU 2 (got ID 1 because its serial number is lower)
1002117E: 00 01 00 00 00 00 00 00 <-- message from PSU 1 (now switched to ID 2 because its serial number is higher)
1001117E: 00 01 00 01 00 00 00 00
1002117E: 00 01 00 00 00 00 00 00
40 Data RequestRequests a data response composed of multiple status messages (including one register each).
Example (to PSU):
108140FE: 00 00 00 00 00 00 00 00
40 Data ReponseExample (from PSU):
1081407F: 01 0E 00 00 00 00 2A 01
1081407F: 01 70 00 00 00 1C DC 31
1081407F: 01 71 00 00 00 00 C7 F5
1081407F: 01 72 00 00 00 00 20 91
1081407F: 01 73 00 00 00 1C 20 9A
1081407F: 01 74 00 00 00 00 03 E6
1081407F: 01 75 00 00 00 00 CD B1
1081407F: 01 76 00 00 00 00 04 00
1081407F: 01 78 00 00 00 03 8B 80
1081407F: 01 7F 00 00 00 00 84 00
1081407F: 01 80 00 00 00 00 6C 00
1081407F: 01 81 00 00 00 00 8C 11
1081407F: 01 82 00 00 00 00 8C 07
1081407E: 01 83 00 00 10 00 00 00
Data bytes:
Register values:
| register id | example | description |
|---|---|---|
01 0E | 00 00 00 00 2A 01 = 10753 Hrs | Operating Hours |
01 70 | 00 00 00 1C DC 31 = 1847W | Input Power ( / 1024 = A) |
01 71 | 00 00 00 00 C7 F5 = 49.99Hz | Input Frequency ( / 1024 = Hz) |
01 72 | 00 00 00 00 20 91 = 8.14A | Input Current ( / 1024 = A) |
01 73 | 00 00 00 1C 20 9A = 1800W | Output Power ( / 1024 = W) |
01 74 | 00 00 00 00 03 E6 = 97.5% | Efficiency ( / 1024 = 0-1) |
01 75 | 00 00 00 00 CD B1 = 51.4V | Output Voltage ( / 1024 = V) |
01 76 | 00 00 00 00 04 00 = 100.0% | Max Output Current* ( / 1024 = 0-1.22) |
01 78 | 00 00 00 03 8B 80 = 226.8V | Input Voltage ( / 1024 = V) |
01 7F | 00 00 00 00 84 00 = 33°C | Output Temperature ( / 1024 = °C) |
01 80 | 00 00 00 00 6C 00 = 27°C | Input Temperature ( / 1024 = °C) |
01 81 | 00 00 00 00 8C 11 = 35.02A | Output Current 1 (fast/unfiltered) ( / 1024 = A) |
01 82 | 00 00 00 00 8C 07 = 35.01A | Output Current 2 (slow/filtered) ( / 1024 = A) |
01 83 | 00 00 10 00 00 00 = ? | Alarm/Status bits (Details under docs/) |
* Not necessarily the set limit, rather what the PSU is currently capable of outputting, see Output current limit
50 Info RequestRequests an info response composed of multiple messages (including one register each).
Example (to PSU): 108150FE: 00 00 00 00 00 00 00 00
50 Info ResponseExample (from PSU):
R4830S1:
1081507F: 00 01 00 00 40 46 12 67
1081507F: 00 02 64 46 85 50 02 AF
1081507F: 00 03 32 31 30 32 33 31
1081507F: 00 04 31 54 52 52 4C 55
1081507F: 00 05 05 00 01 0D 01 0D
1081507E: 00 06 01 01 00 00 00 00
R4850G2:
1081507F: 00 01 00 00 40 68 0e 27
1081507F: 00 02 24 68 23 8c 3c 2f
1081507F: 00 03 32 31 30 32 33 31
1081507F: 00 04 30 48 42 4a 44 30
1081507F: 00 05 01 00 02 01 02 01
1081507E: 00 06 01 01 00 00 00 00
R4875G6:
1081507F: 00 01 00 00 40 8a 11 53
1081507F: 00 02 e6 30 66 10 8f 6e
1081507F: 00 03 32 31 30 32 33 31
1081507F: 00 04 32 4e 46 45 42 54
1081507F: 00 05 01 00 08 06 08 06
1081507E: 00 06 06 09 00 00 00 00
Data bytes:
Registers:
| register id | data | example | description |
|---|---|---|---|
00 01 | ?? ?? xx xx ?? ?? | 00 01 00 00 40 46 12 67 = 35A (R4830S1) /00 01 00 00 40 8a 11 53 = 69A (R4875G5) | Module characteristic data(xx & 0x3FF) / 2 = nominal current |
00 02 | xx xx xx xx xx xx | 00 02 64 46 85 50 02 AF = ? | Serial number |
00 03 | xx xx xx xx xx xx | 00 03 32 31 30 32 33 31 = "210231" | Barcode part 1 (ASCII) |
00 04 | xx xx xx xx xx xx | 00 04 31 54 52 52 4C 55 = "1TRRLU" | Barcode part 2 (ASCII) |
00 05 | xx xx yy yy zz zz | 00 05 05 00 01 0D 01 0D | xx = HW version,yy = DC-DC SW version,zz = PFC SW version |
00 06 | xx yy 00 00 00 00 | 00 06 01 01 00 00 00 00 | xx = Slot ID (top pin / white), yy = Slot ID (bottom pin / black) |
This can be used to determine the physical slot the PSU is in, even though the PSU addresses are negotiated automatically (and thus can change from boot to boot).
On the original backplane, these are connected to resistors / resistor networks / dip switches to set a unique ID for each slot.
The top slot detect pin uses a voltage injected into the pin to set the slot ID:
| tested voltage values | slot id value |
|---|---|
| short to gnd | 01 |
| 0.3-0.7V | 02 |
| 1V | 03 |
| 1.2-1.5V | 04 |
| 1.8V | 05 |
| 2V | 06 |
| 2.3-2.6V | 07 |
| >2.8V | 08 |
The bottom slot detect pin uses a resistor to ground, both to turn on the PSU and encode the slot ID:
| tested resistor values | slot id value |
|---|---|
| short to gnd | 01 |
| 6.3k | 02 |
| 10k | 03 |
| 16.3k to 24k | 04 |
| 34k | 05 |
| 47k | 06 |
| 100k | 07 |
| 147k | 08 |
D2 E-Label RequestRequests an "E-Label" response composed of multiple status messages (including one part of the ASCII response each).
Example (to PSU): 1081D2FE: 00 00 00 00 00 00 00 00
D2 E-Label ResponseExample (from PSU):
1081D27F: 00 01 2F 24 5B 41 72 63
1081D27F: 00 02 68 69 76 65 73 49
1081D27F: 00 03 6E 66 6F 20 56 65
1081D27F: 00 04 72 73 69 6F 6E 5D
[...]
1081D27F: 00 33 3D 30 30 0D 0A 43
1081D27F: 00 34 4C 45 49 43 6F 64
1081D27F: 00 35 65 3D 0D 0A 42 4F
1081D27E: 00 36 4D 3D 0D 0A 00 00
Decodes to:
/$[ArchivesInfo Version]
/$ArchivesInfoVersion=3.0
[Board Properties]
BoardType=EN1MRC3S1A1
BarCode=2102311TRRLUL4000687
Item=02311TRR
Description=Function Module,R4830S1,EN1MRC3S1A1,1U2000W Super High Efficiency Rectifier,DS Special
Manufactured=2020-05-06
VendorName=Huawei
IssueNumber=00
CLEICode=
BOM=
80 Register Set RequestSets the value of a register.
Example (to PSU): 108180FE: 01 34 00 01 00 00 00 00
Data bytes:
Registers:
| reg id | data | example | Persistent | description |
|---|---|---|---|---|
01 00 | 00 00 xx xx xx xx | 53.5V * 1024 = 0x0000D600= 01 00 00 00 00 00 D6 00 | Output voltage (V * 1024) | |
01 01 | 00 00 xx xx xx xx | X | Default output voltage (V * 1024) | |
01 02 | 00 00 xx xx xx xx | ? | Overvoltage protection? (V * 1024) | |
01 03 | 00 00 xx xx xx xx | 10A / 35A (R4830S1) * 1024≈ 0x125= 01 03 00 00 00 00 01 25 | Current limit (0-1.22 * 1024)See Output current limit | |
01 04 | 00 00 xx xx xx xx | X | Default current limit (0-1.22 * 1024)See Output current limit | |
01 09* | 00 xx yy yy yy yy | 4A * 1024 = 0x1000= 01 09 00 01 00 00 10 00 (active bit set) | X** | AC current limitxx = limit activeyy = current (A * 1024)See Input current limit |
01 14* | xx xx 00 00 00 00 | 50% = 0.5 * 25600 = 0x3200= 01 14 32 00 00 00 00 00 | Fan duty cycle (0-1 * 25600)See Fan duty cycle | |
01 32 | 00 xx 00 00 00 00 | Standby00 = PSU on01 = standby | ||
01 34 | 00 xx 00 00 00 00 | X | Fan mode00 = auto01 = max |
* Not supported on R4850G2
** Only the AC input current limit value is persisted, not whether the limit is active.
This means, when setting the limit to 0.1A (too low for startup) and then to 0 (off), the PSU will not start up anymore
(fan will go full speed and output will be <10V). To avoid this, set the limit to a high value (like 20A) before turning it off.
80 Register Set ResponseResponse to setting a register value. Has an error status field in case the value is out of range or the parameter doesn't exist.
Example (from PSU): 1081807E: 01 34 00 01 00 00 00 00
Data bytes:
0 = ok, 2 = parameter error)82 Register Get RequestGets the value from a register.
Seems to work only for status registers (01 70, ...) not for config registers (01 00, ...).
Example (to PSU):
108182FE: 01 34 00 00 00 00 00 00
Data bytes:
82 Register Get ResponseResponse to getting a register value. Has an error status field in case the parameter doesn't exist or can't be read.
Example (to PSU):
1081827E: 01 34 00 01 00 00 00 00
Data bytes:
0 = ok, 2 = parameter error)Registers (in addition to ones from 40 data response);
| register id | data | example | description |
|---|---|---|---|
01 87 * | xx xx yy yy zz zz | 01 87 2D 00 64 00 4B 87 =min. duty 45%duty set 100%19335RPM | Fan control/statusxx = min. duty cycle** (/25600)yy = duty cycle target*** (/ 25600)zz = RPM |
* not supported on R4850G2
** On the R4850G6, the min. duty cycle is based on the current temperature (see Fan control).
On the R4830S1, the min. duty cycle is always equal to the duty cycle target.
*** On both PSUs, the duty cycle target is the greater of both the temperature-based duty cycle and the duty cycle set via CAN.
11 UnsolicitedSent from the PSU unsolicited (without requesting anything).
Due to no documentation being available on any of this, the following is mostly speculation / own findings.
Example (from PSU):
1001117E: 00 01 00 00 00 00 04 97
100011FE: 00 02 00 00 00 00 03 FE
108111FE: 00 03 00 00 00 01 00 00
Messages:
| proto id | address | dir | interval | register id (?) |
|---|---|---|---|---|
20 | 1 (PSU) | 0 (from PSU) | ~377ms | 00 01 |
20 | 0 (broadcast) | 1 (to PSU) | ~3000ms | 00 02 |
21 | 1 (PSU) | 1 (to PSU) | ~377ms | 00 03 |
Due to the different message directions and addresses, and due to the load/current being included, I think these are used for both address negotiation and automatic load sharing between multiple PSUs connected to the same CAN bus.
Due to the messages including the current and being in regular intervals, they might (or at least could) also be used as a coulomb counter.
Data bytes:
| register id | data | example | description |
|---|---|---|---|
00 01 | ?? xx ?? ?? yy yy | 00 01 00 00 00 00 04 97= ready, 114.7% load | xx = ready** status (00 = ready, 01 = not ready)yy = Output load* ( / 1024 = 0-1.22) |
00 02 | ?? ?? ?? ?? xx xx | 00 02 00 00 00 00 03 FE= 99.8% load | xx = Output load* ( / 1024 = 0-1.22) |
00 03 | ?? ?? ?? xx yy yy | 00 03 00 00 00 01 00 00= active, 0% load | xx = active*** status (00 = not active, 01 = active)yy = Output load* ( / 1024 = 0-1.22) |
* The value in 00 01 seems to update faster than the one in 00 03. For calculatung current from this, see Output current limit
** ready: PSU is ready to output voltage/power (AC input available, not faulted, ...)
*** active: device is outputting voltage/power (not booting, not standby, ...)
The CAN communication is powered by the DC side. This means CAN communication is always possible when there is a battery connected, even if there is no AC input present.
For some values (mostly voltage and current) there is a "default" value (which is saved in non-volatile memory)
in addition to the "running" value.
This means, the voltage/current will be reset to these default settings after power loss
or CAN communication loss (after ~60s timeout, shown by flashing yellow light on front panel)
and has to be set again once CAN communication is (re-)established.
Most CAN values have a multiplier of 1024 (50V * 1024 = 51200 = 0xC800).
When setting parameters, the PSU reports an error when the value exceeds the valid range.
Valid ranges (tested with R4830S1 and R4850G6)
A4 00) to 58.6V (EA 67)C0 00) to 58.4V (E9 9A)00 00) to 122% (04 E2)
00 00) or between 30% (1E 00) and 100% (64 00)00 00) or between min. duty cycle (temperature dependent) and 100% (64 00)The output current limit is set as a ratio of the nominal output current (see Info response).
For the R4830S1, this means 1024 = 35A, for the R4850G6 1024 = 52A.
However, 1024 is not the maximum, this field goes to 1250, for example the R4830S1 can output 1250 / 1024 * 35A ≈ 42.7A, but not necessarily at every voltage.
This means, to set a current limit of 10A for the R4830S1,
the register should be set to: 10A / 35A * 1024 ≈ 293 = 00 00 01 25.
The max output current readout (register 01 76) uses the same scale but does not necessarily equal the limit
that has been set, but rather specifies what the PSU is currently set to and capable of outputting.
This includes the output current limit (of course), but also the AC current limit
and possibly also the AC voltage, DC voltage, temperature derating, etc.
Examples (R4850G6):
| DC current limit | AC current limit | AC voltage | DC voltage | Max current readout | Limited by |
|---|---|---|---|---|---|
| 122% (63.5A) | off | 230V | 49.5V | 117% (60.9A) | PSU capacity |
| 50% (26.0A) | off | 230V | 49.5V | 50% (26.0A) | DC limit |
| 100% (52.0A) | 2A | 230V | 49.5V | 17% (9.0A) | AC limit |
Hitting the input/AC current limit (when set to a low value like 5A) can cause the fan to turn off temporarily, even if a fan duty cycle is set. When the output temperature hits a threshold of ~75°C, the fan is turned on again and turned off again at ~65°C. Setting the fan mode to max overrides this and always turns on the fan.
Can only be set to 0 or above the min. duty cycle (other values return an error and reset the internal value to 0 (auto)).
On the R4850G6, the min. duty depends on the temperature
On the R4830S1, the min. duty is the current setpoint (which is probably a bug), so the duty cycle can only be increased or set to 0, meaning to decrease the fan duty cycle, the value has to be set twice.
This information was put together from several sources, such as:
docs/Please consider donating (via GitHub Sponsors) if this project is useful to you.
You can also support this project in other ways:
AI-generated contributions are not welcome and will not be considered.