This chapter describes how to integrate PowerHub, a programmable controller with integrated multi-channel power management, into Home Assistant.
2025.11.2. If you encounter compilation/upload issues, consider switching ESPHome to this version.Open ESPHome Builder in Home Assistant and create an empty configuration file.
Click the NEW DEVICE button in the bottom right corner.
Click CONTINUE in the pop-up box.

Select Empty Configuration.

Name the file (Optional).

Click EDIT on the newly generated configuration file.

Copy the contents of configurations.yaml into the configuration file.

Change network configuration or API information as needed, such as creating an API Encryption Key for authentication:
api:
encryption:
key: "Your_Encryption_Key"Or change the timezone settings:
timezone: Europe/LondonChange to the appropriate timezone:
timezone: Asia/ShanghaiClick SAVE and INSTALL in the top right corner in sequence, then select Manual download.

The code will be generated and the project will be compiled.
When compilation is complete, select Factory format to download the firmware.

Download firmware: Download the Factory Format firmware via the Manual download method in ESPHome Builder.
Flash firmware using web tools:
Open a browser and visit ESPHome Web to upload the firmware.
Connect PowerHub to the host using a USB-C cable, click CONNECT, and select the device connection.

Click INSTALL, select the previously downloaded firmware to upload, then click INSTALL again to flash the firmware to the device.

When flashing is complete, the device will automatically reset.

When the device restarts, it will automatically connect to the previously configured network. Under normal circumstances, the device can be discovered in Settings -> Devices & services.

Click Add to integrate PowerHub into Home Assistant. If an API Encryption Key was previously set, you may need to enter it here for verification.
PowerHub Dashboard Example:

RS485 & CAN Power Output).I2C is a necessary component for configuring the device.
# Example configuration entry
powerhub: never to disable updates. Default is 10s.The Binary Sensor for powerhub is mainly used to detect if the top PMU button is pressed.
binary_sensor:
- platform: powerhub
id: powerhub_binary_sensor
button:
name: "Top PMU Button" The sensors on powerhub report various measured values such as voltage/current.
sensor:
- platform: powerhub
battery_voltage:
name: "Battery Voltage"
id: bat_volt_sensor
battery_current:
name: "Battery Current"
id: bat_curr_sensor
battery_level:
name: "Battery Percentage"
id: bat_level_sensor
grove_red_voltage:
name: "Port.A Voltage"
id: grove_red_volt_sensor
grove_red_current:
name: "Port.A Current"
id: grove_red_curr_sensor
grove_blue_voltage:
name: "Port.C Voltage"
id: grove_blue_volt_sensor
grove_blue_current:
name: "Port.C Current"
id: grove_blue_curr_sensor
can_voltage:
name: "CAN Voltage"
id: can_volt_sensor
can_current:
name: "CAN Current"
id: can_curr_sensor
rs485_voltage:
name: "RS485 Voltage"
id: rs485_volt_sensor
rs485_current:
name: "RS485 Current"
id: rs485_curr_sensor
usb_voltage:
name: "USB Voltage"
id: usb_volt_sensor
usb_current:
name: "USB Current"
id: usb_curr_sensor VAMeter Power switch and the corresponding output channel must be turned on. Readings are only meaningful after the corresponding load is connected.The Text Sensor for powerhub reports power status in text format, as well as the internal firmware/bootloader version of the device.
text_sensor:
- platform: powerhub
charge_status:
name: "Battery Charge Status"
id: bat_charge_status_text_sensor
vin_status:
name: "External Input Power Status"
id: ext_vin_status_text_sensor
firmware_ver:
name: "Internal Firmware Version"
id: int_firm_ver_text_sensor
bootloader_ver:
name: "Bootloader Version"
id: boot_ver_text_sensor The switches for powerhub allow you to enable or disable individual power channels in the frontend.
switch:
- platform: powerhub
led_pwr:
name: "LED Power"
id: led_pwr_switch
usb_pwr:
name: "USB Power"
id: usb_pwr_switch
grove_red_pwr:
name: "Port.A Power"
id: grove_red_pwr_switch
grove_blue_pwr:
name: "Port.C Power"
id: grove_blue_pwr_switch
rs485_can_pwr:
name: "RS485&CAN Power"
id: rs485_can_pwr_switch
vameter_pwr:
name: "VAMeter Power"
id: vameter_pwr_switch
charge_pwr:
name: "Charge Power"
id: charge_pwr_switch
rs485_can_direction:
name: "RS485&CAN Power Output"
id: rs485_can_direction_switch true.
Other options same as Switch.true.
Other options same as Switch.true.
Other options same as Switch.The select for powerhub can be used to switch the USB mode of the USB Type-A or USB Type-C interface.
select:
- platform: powerhub
usb_mode:
name: "USB Mode"
id: usb_mode_select Default, Host for USB-C, or Host for USB-A.
Other options same as Select.The output voltage and current limits for the RS485 & CAN interface can be set via number.
number:
- platform: powerhub
rs485_can_output_voltage:
name: "RS485&CAN Output Voltage"
rs485_can_current_limit:
name: "RS485&CAN Output Current Limit" 3000 mV.
Only takes effect when the switch rs485_can_direction is turned on.
Other options same as Number.13 mA.
Only takes effect when the switch rs485_can_direction is turned on.
Other options same as Number.Each power channel of powerhub comes with a status RGB LED to indicate power status.
light:
- platform: powerhub
usb_c_rgb:
name: "USB C Light"
usb_a_rgb:
name: "USB A Light"
grove_blue_rgb:
name: "Port.C Light"
grove_red_rgb:
name: "Port.A Light"
rs485_can_rgb:
name: "RS485&CAN Light"
bat_charge_rgb:
name: "Battery Charge Light"
pwr_l_rgb:
name: "Power L Light"
pwr_r_rgb:
name: "Power R Light" Lights can be used very conveniently to indicate channel status. You can selectively update the lights based on various Sensor data, such as turning on the lights in the PMU button at startup:
esphome:
...
on_boot:
then:
# Turn on the power (L/R) light
- light.turn_on:
id: led_pwr_l
brightness: 100%
- light.turn_on:
id: led_pwr_r
brightness: 100% Selectively update the top PMU button lights based on battery level readings:

sensor:
- platform: powerhub
...
battery_level:
name: "Battery Percentage"
id: bat_level_sensor
on_value:
- lambda: |-
auto call_1 = id(led_pwr_l).turn_on();
auto call_2 = id(led_pwr_r).turn_on();
auto call_off_1 = id(led_pwr_l).turn_off();
auto call_off_2 = id(led_pwr_r).turn_off();
call_1.set_transition_length(1000);
call_2.set_transition_length(1000);
call_off_1.set_transition_length(1000);
call_off_2.set_transition_length(1000);
call_1.set_color_mode(ColorMode::RGB);
call_2.set_color_mode(ColorMode::RGB);
// if read battery level is unknown
// set the LED color to white
if ( std::isnan(x) ) {
call_1.set_rgb(1.0, 1.0, 1.0);
call_2.set_rgb(1.0, 1.0, 1.0);
call_1.set_brightness(1.0);
call_2.set_brightness(1.0);
call_1.perform();
call_2.perform();
return;
}
if ( x > 80.0f && x <= 100.0f ) {
call_1.set_rgb(0, 1.0, 0);
call_2.set_rgb(0, 1.0, 0);
call_1.set_brightness(1.0);
call_2.set_brightness(1.0);
call_1.perform();
call_2.perform();
} else if ( x > 50.0f && x <= 80.0f ) {
call_1.set_rgb(0, 1.0, 0);
call_2.set_rgb(0, 1.0, 0);
call_1.set_brightness(1.0);
call_2.set_brightness(0.8);
call_1.perform();
call_2.perform();
} else if ( x > 20.0f && x <= 50.0f ) {
call_1.set_rgb(1.0, 0.95, 0.19); // left only one LED on with YELLOW color suggest low power
call_1.perform();
call_off_2.perform();
} else if ( x > 5.0f && x <= 20.0f ){
call_1.set_rgb(1.0, 0.43, 0.32); // left only one LED on with RED color suggest extremely low power
call_1.perform();
call_off_2.perform();
} else {
call_1.set_rgb(1.0, 0.43, 0.32);
call_1.set_brightness(0.8); // almost empty
call_1.perform();
call_off_2.perform();
}
... Alternatively, turn on/off the corresponding LED indicator light when turning on/off a channel switch:
switch:
- platform: powerhub
...
usb_pwr:
name: "USB Power"
id: usb_pwr_switch
on_turn_on:
- light.turn_on:
id: led_usb_a
brightness: 90%
# Color maybe
# red: 100%
# green: 100%
# blue: 100%
- light.turn_on:
id: led_usb_c
brightness: 90%
on_turn_off:
- light.turn_off:
id: led_usb_a
- light.turn_off:
id: led_usb_c
grove_red_pwr:
name: "Port.A Power"
id: grove_red_pwr_switch
on_turn_on:
- light.turn_on:
id: led_grove_red
brightness: 90%
on_turn_off:
- light.turn_off:
id: led_grove_red
grove_blue_pwr:
name: "Port.C Power"
id: grove_blue_pwr_switch
on_turn_on:
- light.turn_on:
id: led_grove_blue
brightness: 90%
on_turn_off:
- light.turn_off:
id: led_grove_blue
rs485_can_pwr:
name: "RS485&CAN Power"
id: rs485_can_pwr_switch
on_turn_on:
- light.turn_on:
id: led_rs485_can
brightness: 90%
on_turn_off:
- light.turn_off:
id: led_rs485_can
charge_pwr:
name: "Charge Power"
id: charge_pwr_switch
restore_mode: RESTORE_DEFAULT_ON
on_turn_on:
- light.turn_on:
id: led_bat_charge
brightness: 90%
on_turn_off:
- light.turn_off:
id: led_bat_charge
... Using pulse/breath light to indicate charging status when battery is charging (requires adding pulse effect to the light):
light:
- platform: powerhub
...
bat_charge_rgb:
id: led_bat_charge
name: "Battery Charge Light"
effects:
- pulse:
name: "Slow Pulse"
transition_length: 500ms
update_interval: 2s
... text_sensor:
- platform: powerhub
charge_status:
name: "Battery Charge Status"
id: bat_charge_status_text_sensor
on_value:
- lambda: |-
static std::string last_state = "";
if (last_state == x) return;
last_state = x;
auto call = id(led_bat_charge).turn_on();
call.set_brightness(0.9);
call.set_color_mode(ColorMode::RGB);
if (x == "Charging") {
// Pulse green
call.set_rgb(0, 1.0, 0);
call.set_effect("Slow Pulse");
} else if (x == "Discharging") {
// Solid green
call.set_rgb(0, 1.0, 0);
call.set_effect("None");
} else {
// Solid white
call.set_rgb(1.0, 1.0, 1.0);
call.set_effect("None");
}
call.perform(); powerhub has a built-in RX8130 RTC chip, which can serve as the time source for the device.
time:
- platform: powerhub
id: powerhub_time powerhub.write_time ActionThis Action triggers syncing the current system time to the RTC hardware.
on_...:
- powerhub.write_time
# If powerhub id needs to be specified
- powerhub.write_time:
id: powerhub_time powerhub.read_time ActionThis Action triggers syncing the current system time from the RTC hardware.
update_interval) on_...:
- powerhub.read_time
# If powerhub id needs to be specified
- powerhub.read_time:
id: powerhub_time In general, at least one additional time source is required for synchronization with the RTC. Such external time sources may not always be available (e.g., restricted network). To ensure that the system time is valid and reliable, the system should read the RTC once at startup and then attempt to sync with a reliable external time source. After a successful sync with another time source, that time can then be written back to the RTC to resync it.
esphome:
on_boot:
then:
# Read RTC time once at system startup
powerhub.read_time:
time:
- platform: powerhub
# If the external RTC is not more accurate than the internal clock, repeated sync is not needed
timezone: Asia/Shanghai
update_interval: never
- platform: homeassistant
# Change to repeat sync attempts via network ...
on_time_sync:
then:
# ... update RTC after successful sync
powerhub.write_time: