This tool helps you create configuration files for your B2500 device and generate the necessary firmware without requiring any technical knowledge or software installation on your computer. You can do everything through your web browser.
For the best experience with this project, I recommend using an ESP32-S3. You can purchase one from these links:
When using these boards, set the following options:
- Board:
esp32-s3-devkitc-1 - Variant:
esp32s3
- Visit https://tomquist.github.io/esphome-b2500/
- Fill out the form with your desired configuration settings. The default values are provided for convenience.
- Once you have filled out the form, the configuration will be automatically generated and displayed.
- You can download the YAML configuration file by clicking the "Download YAML" button. This configuration can directly be used to build an ESPHome image, e.g. through the Home Assistant ESPHome Addon. Alternatively you can directly build an image for your ESP32 and flash it via the ESPHome web flasher. Read the following section for detailed instructions.
- Click the "Build Image" button.
- Click "Start Build" and follow the instructions
- Extract the firmware binary from the downloaded ZIP file.
- Connect your ESP32 via USB
- Go to the ESPHome Web Installer: ESPHome Web Installer.
- Click the "Install" button.
- Select "Choose File" and upload the extracted firmware binary.
- Follow the on-screen instructions to select the connected ESP32 device and flash the firmware.
Find a list of all MQTT topics, depending on the selected configuration version:
Legacy
Find a detailed list of topics [here](https://github.com/noone2k/hm2500pub/wiki/ESP32-MQTT-TOPICS).Native ESPHome component
The base topic prefix is b2500, unless you changed it via "MQTT > Topic". Replace {storage} with 1, 2 or 3 for the respective device, and {timer} with a number from 1 to 5 for timer settings.
| Description | Read Topic | Write Topic | Available in version |
|---|---|---|---|
| Total System Input Power | b2500/S/pv/power | - | v1, v2 |
| Total System Output Power | b2500/S/power/power | - | v1, v2 |
| Total System Daily Energy Input | b2500/S/pv/energy | - | v1, v2 |
| Total System Daily Energy Output | b2500/S/power/energy | - | v1, v2 |
| Total System Remaining Capacity | b2500/S/battery/remaining_capacity | - | v1, v2 |
| Controller Restart | - | b2500/restart/set | v1, v2 |
| Description | Read Topic | Write Topic | Available in version |
|---|---|---|---|
| Debug Logs | b2500/debug | - | v1, v2 |
| ESP32 Temperature | b2500/esp32/temperature | - | v1, v2 |
| ESP32 Uptime | b2500/esp32/uptime | - | v1, v2 |
| Description | Read Topic | Write Topic | Available in version |
|---|---|---|---|
| Device Generation | b2500/{storage}/device/generation | - | v1, v2 |
| Device Name | b2500/{storage}/device/name | - | v1, v2 |
| Device Type | b2500/{storage}/device/type | - | v1, v2 |
| Device ID | b2500/{storage}/device/id | - | v1, v2 |
| Device Firmware Version | b2500/{storage}/device/fw_version | - | v1, v2 |
| Device MAC Address | b2500/{storage}/device/ble_mac | - | v1, v2 |
| FC41D Firmware Version | b2500/{storage}/device/fc41d_fw | - | v1, v2 |
| Device Scene | b2500/{storage}/device/scene | - | v1, v2 |
| Device Region | b2500/{storage}/device/region | - | v1, v2 |
| Last Response | b2500/{storage}/device/last_response | - | v1, v2 |
| Device Time | b2500/{storage}/device/time | - | v2 only |
| Description | Read Topic | Write Topic | Available in version |
|---|---|---|---|
| WiFi SSID | b2500/{storage}/device/wifi_ssid | - | v1, v2 |
| WiFi Connected Status | b2500/{storage}/device/wifi_ok | - | v1, v2 |
| WiFi Configuration | - | b2500/{storage}/wifi/set | v1, v2 |
| MQTT Connected Status | b2500/{storage}/device/mqtt_ok | - | v1, v2 |
| MQTT Configuration | - | b2500/{storage}/mqtt/set | v1, v2 |
| MQTT Reset | - | b2500/{storage}/mqtt/reset | v2 only |
| Bluetooth Status | b2500/{storage}/device/ble_ok | - | v1, v2 |
| Bluetooth Enable | b2500/{storage}/bluetooth/enabled | b2500/{storage}/bluetooth/enabled/set | v1, v2 |
| Description | Read Topic | Write Topic | Available in version |
|---|---|---|---|
| PV Input 1 Power | b2500/{storage}/pv1/power | - | v1, v2 |
| PV Input 2 Power | b2500/{storage}/pv2/power | - | v1, v2 |
| Total Input Power | b2500/{storage}/pv/power | - | v1, v2 |
| Total System Input Power | b2500/S/pv/power | - | v1, v2 |
| Output 1 Power | b2500/{storage}/power1/power | - | v1, v2 |
| Output 2 Power | b2500/{storage}/power2/power | - | v1, v2 |
| Total Output Power | b2500/{storage}/power/power | - | v1, v2 |
| Total System Output Power | b2500/S/power/power | - | v1, v2 |
| Daily Energy Input | b2500/{storage}/pv/energy | - | v1, v2 |
| Daily Energy Output | b2500/{storage}/power/energy | - | v1, v2 |
| Total System Daily Energy Input | b2500/S/pv/energy | - | v1, v2 |
| Total System Daily Energy Output | b2500/S/power/energy | - | v1, v2 |
| Description | Read Topic | Write Topic | Available in version |
|---|---|---|---|
| PV Input 1 Active | b2500/{storage}/pv1/active | - | v1, v2 |
| PV Input 2 Active | b2500/{storage}/pv2/active | - | v1, v2 |
| PV Input 1 Transparent | b2500/{storage}/pv1/transparent | - | v1, v2 |
| PV Input 2 Transparent | b2500/{storage}/pv2/transparent | - | v1, v2 |
| Output 1 Active | b2500/{storage}/power1/active | - | v1, v2 |
| Output 2 Active | b2500/{storage}/power2/active | - | v1, v2 |
| Output 1 Enabled | b2500/{storage}/power1/enabled | b2500/{storage}/power1/enabled/set | v1 only |
| Output 2 Enabled | b2500/{storage}/power2/enabled | b2500/{storage}/power2/enabled/set | v1 only |
| Extension 1 Connected | b2500/{storage}/extern1/connected | - | v1, v2 |
| Extension 2 Connected | b2500/{storage}/extern2/connected | - | v1, v2 |
| Temperature 1 | b2500/{storage}/device/temp1 | - | v1, v2 |
| Temperature 2 | b2500/{storage}/device/temp2 | - | v1, v2 |
| Description | Read Topic | Write Topic | Available in version |
|---|---|---|---|
| Battery Level (SOC) | b2500/{storage}/battery/remaining_percent | - | v1, v2 |
| Battery Capacity | b2500/{storage}/battery/remaining_capacity | - | v1, v2 |
| Cell Voltage Data | b2500/{storage}/battery/cell_voltage | - | v1, v2 |
| Charge Mode | b2500/{storage}/battery/charge_mode | b2500/{storage}/battery/charge_mode/set | v1, v2 |
| Discharge Threshold | b2500/{storage}/battery/discharge_threshold | b2500/{storage}/battery/discharge_threshold/set | v1 only |
| Depth of Discharge | b2500/{storage}/battery/dod | b2500/{storage}/battery/dod/set | v1, v2 |
| Description | Read Topic | Write Topic | Available in version |
|---|---|---|---|
| Smart Meter Connected | b2500/{storage}/smartmeter/connected | - | v2 only |
| Smart Meter Enabled | b2500/{storage}/smartmeter/enabled | b2500/{storage}/smartmeter/enabled/set | v2 only |
| Smart Meter Power Out | b2500/{storage}/smartmeter/out | - | v2 only |
| Smart Meter Value | b2500/{storage}/smartmeter/value | - | v2 only |
| Description | Read Topic | Write Topic | Available in version |
|---|---|---|---|
| Timer Enabled | b2500/{storage}/timer/{timer}/enabled | b2500/{storage}/timer/{timer}/enabled/set | v2 only |
| Timer Start Time | b2500/{storage}/timer/{timer}/start | b2500/{storage}/timer/{timer}/start/set | v2 only |
| Timer End Time | b2500/{storage}/timer/{timer}/end | b2500/{storage}/timer/{timer}/end/set | v2 only |
| Timer Output Power | b2500/{storage}/timer/{timer}/power | b2500/{storage}/timer/{timer}/power/set | v2 only |
Replace {timer} with the timer slot number (1 to 5). Each slot is exposed as an individual Home Assistant entity, so the write topics take the command payload of that entity type:
- Timer Enabled:
ONorOFF - Timer Start Time / Timer End Time: a JSON object
{"hour": 8, "minute": 0, "second": 0}(each field is an optional integer; ESPHome time entities use JSON, not aHH:MM:SSstring) - Timer Output Power: an integer number of watts, e.g.
500
Older devices (firmware < 218) only expose 3 timer slots; slots 4 and 5 require newer firmware.
| Description | Read Topic | Write Topic | Available in version |
|---|---|---|---|
| Device Reboot | - | b2500/{storage}/reboot/set | v1, v2 |
| Factory Reset | - | b2500/{storage}/factory_settings/set | v1, v2 |
- Cell Voltage Data (
b2500/{storage}/battery/cell_voltage):
{
"cells": [3.325, 3.324, 3.324, 3.324, 3.324, 3.325, 3.325, 3.324, 3.323, 3.324, 3.324, 3.323, 3.325, 3.323],
"min": 3.323,
"max": 3.325,
"avg": 3.324071429,
"sum": 46.537,
"delta": 0.002
}Minimal native ESPHome component
The base topic prefix is configurable via mqtt.topic, defaulting to b2500. All device-specific topics start with {topic_prefix}/{storage}/:
- Replace
{topic_prefix}with the configured MQTT topic prefix (defaults to "b2500") - Replace
{storage}with device number (1, 2, etc.) - Replace
{output}with output number (1 or 2) {grid_power_topic},{limit_state_topic}, and{limit_cmd_topic}are configurable for PowerZero feature- Power meter topics are only available when the feature is enabled in configuration
- PowerZero features are only available when enabled in configuration
| Description | Read Topic | Write Topic | Available in version |
|---|---|---|---|
| Debug Logs | {topic_prefix}/debug | - | v1, v2 |
| ESP32 Temperature | {topic_prefix}/esp32/temperature | - | v1, v2 |
| ESP32 Uptime | {topic_prefix}/esp32/uptime | - | v1, v2 |
| Total System Energy In | {topic_prefix}/S/pv/energy | - | v1, v2 |
| Total System Energy Out | {topic_prefix}/S/power/energy | - | v1, v2 |
| Controller Restart | - | {topic_prefix}/restart/set | v1, v2 |
| Description | Read Topic | Write Topic | Available in version |
|---|---|---|---|
| Device Info | {topic_prefix}/{storage}/device | - | v1, v2 |
| Runtime Info | {topic_prefix}/{storage}/runtime | - | v1, v2 |
| Cell Info | {topic_prefix}/{storage}/cell | - | v1, v2 |
| WiFi Info | {topic_prefix}/{storage}/wifi | - | v1, v2 |
| FC41D Info | {topic_prefix}/{storage}/fc41d | - | v1, v2 |
| Timer Info | {topic_prefix}/{storage}/timer | - | v2 only |
| Description | Read Topic | Write Topic | Value Format Example | Available in version |
|---|---|---|---|---|
| Bluetooth Status | {topic_prefix}/{storage}/bluetooth/enabled | {topic_prefix}/{storage}/bluetooth/enabled/set | "ON" or "OFF" | v1, v2 |
| WiFi Configuration | - | {topic_prefix}/{storage}/wifi/set | {"ssid": "network_name", "password": "wifi_password"} |
v1, v2 |
| MQTT Configuration | - | {topic_prefix}/{storage}/mqtt/set | {"host": "mqtt.local", "port": 1883, "username": "user", "password": "pass"} |
v1, v2 |
| MQTT Reset | - | {topic_prefix}/{storage}/mqtt/reset | PRESS |
v2 only |
| Description | Read Topic | Write Topic | Value Format Example | Available in version |
|---|---|---|---|---|
| Timer Info | {topic_prefix}/{storage}/timer | - | see Timer Info | v2 only |
| Set Single Timer Slot | - | {topic_prefix}/{storage}/timer/{timer}/set | {"enabled": true, "outputPower": 500, "start": {"hour": 8, "minute": 0}, "end": {"hour": 17, "minute": 0}} |
v2 only |
| Set All Timer Slots | - | {topic_prefix}/{storage}/timer/set | {"enabled": true, "outputPower": 500, "start": {"hour": 8, "minute": 0}, "end": {"hour": 17, "minute": 0}} |
v2 only |
Replace {timer} with the timer slot number (1 to 5). Publish the JSON payload to {topic_prefix}/{storage}/timer/{timer}/set to change a single timer slot, or to {topic_prefix}/{storage}/timer/set to write all slots at once. See Set Timer Configuration below for the full payload format, the list of optional fields, and important notes.
| Description | Read Topic | Write Topic | Value Format Example | Available in version |
|---|---|---|---|---|
| Device Reboot | - | {topic_prefix}/{storage}/reboot/set | PRESS |
v1, v2 |
| Factory Reset | - | {topic_prefix}/{storage}/factory_settings/set | PRESS |
v1, v2 |
| Hardware Reset | - | {topic_prefix}/{storage}/hardware_reset/set | PRESS |
v1, v2 |
| Charge Mode | - | {topic_prefix}/{storage}/charge_mode/set | "LoadFirst" or "SimultaneousChargeAndDischarge" (V2) or "PV2Passthrough" (V1) | v1, v2 |
| Discharge Threshold | - | {topic_prefix}/{storage}/discharge_threshold/set | Integer value (watts) | v1 only |
| Depth of Discharge | - | {topic_prefix}/{storage}/dod/set | Integer value (percent) | v1 only |
| Output Enable | - | {topic_prefix}/{storage}/power{output}/enabled/set | "ON" or "OFF" | v1 only |
| SmartMeter / Adaptive Mode Enable | {topic_prefix}/{storage}/smartmeter/enabled | {topic_prefix}/{storage}/smartmeter/enabled/set | "ON" or "OFF" | v2 only |
| Surplus Feed-in Enable | {topic_prefix}/{storage}/device/surplus_feed_in | {topic_prefix}/{storage}/device/surplus_feed_in/set | "ON" or "OFF" | v2 only |
Payloads for the write topics above are sent as plain (non-JSON) MQTT messages. The .../reboot/set, .../factory_settings/set and .../hardware_reset/set topics are momentary buttons and require the exact payload PRESS (case-sensitive) — any other payload is ignored (ESPHome logs a warning).
| Description | Read Topic | Write Topic | Available in version |
|---|---|---|---|
| PowerZero Enable | {topic_prefix}/npw/enabled | {topic_prefix}/npw/enabled/set | v1, v2 |
| Maximum Limit | {topic_prefix}/npw/max_limit | {topic_prefix}/npw/max_limit/set | v1, v2 |
| Grid Power Subscription | {grid_power_topic} | - | v1, v2 |
| OpenDTU Limit | {limit_state_topic} | {limit_cmd_topic} | v1, v2 |
| Description | Read Topic | Write Topic | Available in version |
|---|---|---|---|
| Voltage | {topic_prefix}/voltage | - | v1, v2 |
| Current | {topic_prefix}/current | - | v1, v2 |
| Power | {topic_prefix}/power | - | v1, v2 |
| Frequency | {topic_prefix}/frequency | - | v1, v2 |
| Daily Energy | {topic_prefix}/energy_daily | - | v1, v2 |
{
"cells": [3.325, 3.324, 3.324, 3.324, 3.324, 3.325, 3.325, 3.324, 3.323, 3.324, 3.324, 3.323, 3.325, 3.323],
"min": 3.323,
"max": 3.325,
"avg": 3.324071429,
"sum": 46.537,
"delta": 0.002
}{
"in1": {
"active": true,
"transparent": false,
"power": 120
},
"in2": {
"active": true,
"transparent": false,
"power": 80
},
"soc": 85,
"capacity": 2000,
"deviceVersion": "1.2.3",
"chargeMode": "LoadFirst",
"out1": {
"active": true,
"power": 100,
"enabled": true
},
"out2": {
"active": true,
"power": 50,
"enabled": true
},
"dod": 80,
"wifiConnected": true,
"mqttConnected": true,
"dischargeThreshold": 20,
"scene": "DAY",
"region": "EU",
"extern": {
"connected1": false,
"connected2": false
},
"time": "14:30",
"temperature": {
"low": 25,
"high": 35
}
}{
"adaptiveModeEnabled": true,
"smartMeter": {
"connected": true,
"reading": 1500,
"power": 800,
"unknown": 0
},
"timer1": {
"enabled": true,
"outputPower": 500,
"start": {
"hour": 8,
"minute": 0
},
"end": {
"hour": 17,
"minute": 0
}
}
// timer2 through timer5 follow same format
}There are two write topics for the discharge timer schedule, both accepting the same JSON payload:
{topic_prefix}/{storage}/timer/{timer}/set– writes a single timer slot. Replace{timer}with the slot number (1–5, matchingtimer1…timer5in the Timer Info read topic). Prefer this topic.{topic_prefix}/{storage}/timer/set– writes the payload to all timer slots at once.
{
"enabled": true,
"outputPower": 500,
"start": { "hour": 8, "minute": 0 },
"end": { "hour": 17, "minute": 0 }
}Fields:
| Field | Type | Description |
|---|---|---|
enabled |
boolean | Whether the timer slot is active. |
outputPower |
integer | Discharge output power in watts while the timer is active. |
start.hour / start.minute |
integer | Start time of the discharge window (hour 0–23, minute 0–59). |
end.hour / end.minute |
integer | End time of the discharge window (hour 0–23, minute 0–59). |
All fields are optional. Only the values present in the payload are written; any omitted field keeps its current value on the device. For example, to change only the output power of slot 1 without touching its schedule, publish { "outputPower": 800 } to {topic_prefix}/{storage}/timer/1/set.
⚠️ Do not use the timers for a fast control loop (e.g. zero-export regulation). Every write is persisted to the device's flash/EEPROM over BLE, which has a limited number of write cycles — writing the timers frequently will wear it out and eventually damage the device. The timers are meant for occasional schedule changes, not for continuously steering output power. For a control loop, drive the output limit dynamically instead (e.g. via hm2mqtt, which does not write to flash by default).Note: the all-slots
timer/settopic writes every slot in one message. V2 devices with firmware < 218 only have 3 timer slots, while newer firmware has 5; the configuration always handles 5 slots, so on a 3-slot device writing totimer/setproduces harmless log warnings such asSetTimerAction: invalid timer index 3 (valid range: 0-2). The valid slots are still updated; the out-of-range slots are ignored. The per-slottimer/{timer}/settopic only touches the slot you address (and only warns if that specific slot doesn't exist).
The b2500 component is a custom ESPHome external component for monitoring and controlling B2500 portable power storage devices over Bluetooth Low Energy (BLE). It supports two device generations (V1 and V2) and exposes sensors, binary sensors, switches, selects, numbers, buttons, text sensors, and datetime entities to Home Assistant.
The component follows a hub pattern: a central b2500 hub communicates with the device via BLE, and platform sub-components (sensor, switch, etc.) attach to it. Each platform block requires a generation key set to 1 or 2, which controls which entities are available.
# Example: loading the external component
external_components:
- source: github://tomquist/esphome-b2500
components: [b2500]The b2500 hub component handles BLE communication and polling. It requires the esp32_ble_tracker and ble_client components, as well as a time component for clock synchronization.
# Example configuration entry
esp32_ble_tracker:
ble_client:
- mac_address: "AA:BB:CC:DD:EE:FF"
id: my_ble_client
time:
- platform: sntp
id: sntp_time
b2500:
id: b2500_device
generation: 2- generation (Required, int): The device generation. Must be
1or2. - id (Optional, ID): Manually specify the component ID.
- update_interval (Optional, Time): The interval to poll the device. Defaults to
10s. - time_id (Optional, ID): ID of a
timecomponent for clock synchronization. Automatically detected if only one time component exists. - All other options from BLE Client.
- on_device_info (Optional, Automation): Triggered when device information is received from the B2500. The trigger variable
xcontains device info fields. - on_runtime_info (Optional, Automation): Triggered when runtime information (power, SOC, temperatures, etc.) is received. The trigger variable
xcontains runtime fields. - on_cell_info (Optional, Automation): Triggered when battery cell information is received. The trigger variable
xcontains cell voltage data. - on_wifi_info (Optional, Automation): Triggered when WiFi information is received. The trigger variable
xcontains WiFi status fields. - on_fc41d_info (Optional, Automation): Triggered when FC41D module information is received. The trigger variable
xcontains FC41D firmware data. - on_timer_info (Optional, Automation): V2 only. Triggered when timer configuration is received. The trigger variable
xcontains timer settings.
# Example: using automation triggers
b2500:
id: b2500_device
generation: 2
on_runtime_info:
then:
- logger.log: "Runtime info received"
on_timer_info:
then:
- logger.log: "Timer info received"The b2500 sensor platform exposes power, battery, and temperature measurements.
# Example configuration entry
sensor:
- platform: b2500
b2500_id: b2500_device
generation: 2
soc:
name: "Battery SOC"
in1_power:
name: "PV Input 1"
in2_power:
name: "PV Input 2"
out_total_power:
name: "Total Output"
capacity:
name: "Remaining Capacity"- generation (Required, int):
1or2. - b2500_id (Optional, ID): ID of the parent
b2500component. Can be omitted if only oneb2500hub exists. - publish_unchanged_sensor_values (Optional, boolean): Whether to publish sensor updates even when the value has not changed. Defaults to
true.
- soc (Optional): Battery state of charge. Unit:
%, device class:battery, state class:measurement, accuracy: 1 decimal. - in1_power (Optional): PV input 1 power. Unit:
W, device class:power, state class:measurement. - in2_power (Optional): PV input 2 power. Unit:
W, device class:power, state class:measurement. - in_total_power (Optional): Total PV input power. Unit:
W, device class:power, state class:measurement. - out1_power (Optional): Output 1 power. Unit:
W, device class:power, state class:measurement. - out2_power (Optional): Output 2 power. Unit:
W, device class:power, state class:measurement. - out_total_power (Optional): Total output power. Unit:
W, device class:power, state class:measurement. - capacity (Optional): Remaining battery capacity. Unit:
Wh, device class:energy_storage, state class:measurement. - wifi_rssi (Optional): WiFi signal strength. Device class:
signal_strength, state class:measurement. - temperature_low (Optional): Lower temperature reading. Unit:
°C, device class:temperature, state class:measurement. - temperature_high (Optional): Upper temperature reading. Unit:
°C, device class:temperature, state class:measurement.
All sensor options from Sensor are supported for each entry.
- adaptive_power_out (Optional): Adaptive mode output power. Unit:
W, device class:power, state class:measurement. - smart_meter_reading (Optional): Smart meter reading. Unit:
VA, state class:measurement. - daily_total_battery_charge (Optional): Daily total battery charge. Unit:
Wh, device class:energy, state class:total_increasing. - daily_total_battery_discharge (Optional): Daily total battery discharge. Unit:
Wh, device class:energy, state class:total_increasing. - daily_total_load_charge (Optional): Daily total load charge. Unit:
Wh, device class:energy, state class:total_increasing. - daily_total_load_discharge (Optional): Daily total load discharge. Unit:
Wh, device class:energy, state class:total_increasing.
The b2500 binary sensor platform exposes connectivity and input/output status.
# Example configuration entry
binary_sensor:
- platform: b2500
b2500_id: b2500_device
generation: 1
wifi_connected:
name: "WiFi Connected"
in1_active:
name: "PV1 Active"
out1_active:
name: "Output 1 Active"- generation (Required, int):
1or2. - b2500_id (Optional, ID): ID of the parent
b2500component.
- wifi_connected (Optional): Whether the device's WiFi is connected.
- mqtt_connected (Optional): Whether the device's MQTT client is connected.
- in1_active (Optional): Whether PV input 1 is active (producing power).
- in2_active (Optional): Whether PV input 2 is active (producing power).
- in1_transparent (Optional): Whether PV input 1 is in transparent pass-through mode.
- in2_transparent (Optional): Whether PV input 2 is in transparent pass-through mode.
- out1_active (Optional): Whether output 1 is active (delivering power).
- out2_active (Optional): Whether output 2 is active (delivering power).
- extern1_connected (Optional): Whether external battery module 1 is connected.
- extern2_connected (Optional): Whether external battery module 2 is connected.
All options from Binary Sensor are supported for each entry.
- smart_meter_connected (Optional): Whether a smart meter is connected.
The b2500 switch platform provides controllable switches. The available switches differ between V1 and V2 devices.
# Example configuration entry (V1)
switch:
- platform: b2500
b2500_id: b2500_device
generation: 1
out1:
name: "Output 1 Enabled"
out2:
name: "Output 2 Enabled"# Example configuration entry (V2)
switch:
- platform: b2500
b2500_id: b2500_device
generation: 2
adaptive_mode:
name: "Adaptive Mode"
surplus_feed_in:
name: "Surplus Feed-in"
timer1_enabled:
name: "Timer 1"- generation (Required, int):
1or2. - b2500_id (Optional, ID): ID of the parent
b2500component.
- out1 (Optional): Enable or disable output 1. Entity category:
config. - out2 (Optional): Enable or disable output 2. Entity category:
config.
- adaptive_mode (Optional): Enable or disable adaptive power mode. Entity category:
config. - surplus_feed_in (Optional): Enable or disable surplus feed-in to grid. Entity category:
config. - timer1_enabled (Optional): Enable or disable timer 1. Entity category:
config. - timer2_enabled (Optional): Enable or disable timer 2. Entity category:
config. - timer3_enabled (Optional): Enable or disable timer 3. Entity category:
config. - timer4_enabled (Optional): Enable or disable timer 4. Entity category:
config. - timer5_enabled (Optional): Enable or disable timer 5. Entity category:
config.
All options from Switch are supported for each entry.
The b2500 select platform provides a dropdown for the battery charge mode.
# Example configuration entry
select:
- platform: b2500
b2500_id: b2500_device
generation: 1
charge_mode:
name: "Charge Mode"- generation (Required, int):
1or2. - b2500_id (Optional, ID): ID of the parent
b2500component. - charge_mode (Optional): Battery charge mode selection. Available options depend on generation:
- V1:
load_first,pv2_passthrough - V2:
load_first,simultaneous_charge_and_discharge
- V1:
All options from Select are supported.
The b2500 number platform provides adjustable numeric settings.
# Example configuration entry (V1)
number:
- platform: b2500
b2500_id: b2500_device
generation: 1
dod:
name: "Depth of Discharge"
discharge_threshold:
name: "Discharge Threshold"# Example configuration entry (V2)
number:
- platform: b2500
b2500_id: b2500_device
generation: 2
dod:
name: "Depth of Discharge"
timer1_output_power:
name: "Timer 1 Output Power"
timer2_output_power:
name: "Timer 2 Output Power"- generation (Required, int):
1or2. - b2500_id (Optional, ID): ID of the parent
b2500component.
- dod (Optional): Depth of discharge — the maximum percentage of the battery that can be used. Range:
0–100, step:1, unit:%. Entity category:config.
- discharge_threshold (Optional): Minimum power threshold for discharge. Range:
0–999, step:1, unit:W. Entity category:config.
- timer1_output_power (Optional): Output power for timer 1. Range:
50–800, step:1, unit:W. Entity category:config. - timer2_output_power (Optional): Output power for timer 2. Range:
50–800, step:1, unit:W. Entity category:config. - timer3_output_power (Optional): Output power for timer 3. Range:
50–800, step:1, unit:W. Entity category:config. - timer4_output_power (Optional): Output power for timer 4. Range:
50–800, step:1, unit:W. Entity category:config. - timer5_output_power (Optional): Output power for timer 5. Range:
50–800, step:1, unit:W. Entity category:config.
All options from Number are supported for each entry.
The b2500 button platform provides device control buttons.
# Example configuration entry
button:
- platform: b2500
b2500_id: b2500_device
generation: 1
reboot:
name: "Reboot"
factory_reset:
name: "Factory Reset"
hardware_reset:
name: "Hardware Reset"- generation (Required, int):
1or2. - b2500_id (Optional, ID): ID of the parent
b2500component.
- reboot (Optional): Reboot the B2500 device.
- factory_reset (Optional): Reset the B2500 device to factory defaults.
- hardware_reset (Optional): Reset the BLE connection hardware on the B2500.
All options from Button are supported for each entry.
The b2500 text sensor platform exposes device information as text values.
# Example configuration entry
text_sensor:
- platform: b2500
b2500_id: b2500_device
generation: 1
firmware_version:
name: "Firmware Version"
device_id:
name: "Device ID"
cell_voltage:
name: "Cell Voltage"- generation (Required, int):
1or2. - b2500_id (Optional, ID): ID of the parent
b2500component.
- firmware_version (Optional): The device firmware version string. Entity category:
diagnostic. - device_type (Optional): The device type identifier. Entity category:
diagnostic. - device_id (Optional): The unique device ID. Entity category:
diagnostic. - mac_address (Optional): The device BLE MAC address. Entity category:
diagnostic. - fc41d_version (Optional): The FC41D module firmware version. Entity category:
diagnostic. - wifi_ssid (Optional): The WiFi network the device is connected to. Entity category:
diagnostic. - scene (Optional): The current scene, e.g.
DAYorNIGHT. Entity category:diagnostic. - region (Optional): The configured device region. Entity category:
diagnostic. - cell_voltage (Optional): Battery cell voltage data as JSON. Contains
cellsarray,min,max,avg,sum, anddeltavalues. Entity category:diagnostic. - last_response (Optional): Timestamp of the last received BLE response. Entity category:
diagnostic.
- device_time (Optional): The current time reported by the device. Entity category:
diagnostic.
All options from Text Sensor are supported for each entry.
The b2500 datetime platform exposes timer start and end times as time entities. This platform is only available for V2 devices.
# Example configuration entry
datetime:
- platform: b2500
b2500_id: b2500_device
generation: 2
timer1_start:
name: "Timer 1 Start"
timer1_end:
name: "Timer 1 End"
timer2_start:
name: "Timer 2 Start"
timer2_end:
name: "Timer 2 End"- generation (Required, int): Must be
2. - b2500_id (Optional, ID): ID of the parent
b2500component. - timer1_start / timer1_end (Optional): Start and end time for timer 1.
- timer2_start / timer2_end (Optional): Start and end time for timer 2.
- timer3_start / timer3_end (Optional): Start and end time for timer 3.
- timer4_start / timer4_end (Optional): Start and end time for timer 4.
- timer5_start / timer5_end (Optional): Start and end time for timer 5.
All options from Datetime are supported for each entry.
The b2500 component registers several actions for use in automations. All templatable parameters support lambdas.
Configure the WiFi credentials on the B2500 device.
on_...:
then:
- b2500.set_wifi:
id: b2500_device
ssid: !secret wifi_ssid
password: !secret wifi_password- id (Required, ID): The
b2500component to control. - ssid (Required, string, templatable): The WiFi SSID.
- password (Required, string, templatable): The WiFi password.
Configure the MQTT connection on the B2500 device.
on_...:
then:
- b2500.set_mqtt:
id: b2500_device
host: !secret mqtt_host
port: 1883
username: !secret mqtt_username
password: !secret mqtt_password
ssl: false- id (Required, ID): The
b2500component to control. - host (Required, string, templatable): The MQTT broker hostname.
- port (Required, int, templatable): The MQTT broker port.
- username (Required, string, templatable): The MQTT username.
- password (Required, string, templatable): The MQTT password.
- ssl (Optional, boolean): Whether to use SSL. Defaults to
false.
Reset the MQTT configuration on the B2500 device to defaults.
on_...:
then:
- b2500.reset_mqtt:
id: b2500_device- id (Required, ID): The
b2500component to control.
Synchronize the B2500 device clock.
on_...:
then:
- b2500.set_datetime:
id: b2500_device
datetime: !lambda 'return id(sntp_time).now();'- id (Required, ID): The
b2500component to control. - datetime (Required, datetime): The date and time to set. Accepts a lambda returning an
ESPTimestruct or a static datetime value.
Reboot the B2500 device.
on_...:
then:
- b2500.reboot:
id: b2500_device- id (Required, ID): The
b2500component to reboot.
Reset the B2500 device to factory defaults.
on_...:
then:
- b2500.factory_reset:
id: b2500_device- id (Required, ID): The
b2500component to reset.
Set the depth of discharge (maximum usable battery percentage).
on_...:
then:
- b2500.set_dod:
id: b2500_device
dod: 80- id (Required, ID): The
b2500component to control. - dod (Required, int, templatable): The depth of discharge percentage (0–100).
Set the battery charge mode.
on_...:
then:
- b2500.set_charge_mode:
id: b2500_device
charge_mode: load_first- id (Required, ID): The
b2500component to control. - charge_mode (Required, enum, templatable): One of
load_first,pv2_passthrough(V1), orsimultaneous_charge_and_discharge(V2).
Enable or disable a power output on V1 devices.
on_...:
then:
- b2500.set_out_active:
id: b2500_device
generation: 1
output: 1
active: true- id (Required, ID): The
b2500V1 component to control. - generation (Required, int): Must be
1. - output (Required, int, templatable): The output number (
1or2). - active (Required, boolean, templatable): Whether to enable (
true) or disable (false) the output.
Set the minimum power threshold for discharge on V1 devices.
on_...:
then:
- b2500.set_discharge_threshold:
id: b2500_device
generation: 1
threshold: 100- id (Required, ID): The
b2500V1 component to control. - generation (Required, int): Must be
1. - threshold (Required, int, templatable): The discharge threshold in watts (0–999).
Configure a timer on V2 devices. At least one optional field besides timer must be provided. Fields that are not specified retain their current value.
on_...:
then:
- b2500.set_timer:
id: b2500_device
generation: 2
timer: 0
enabled: true
output_power: 500
start_hour: 8
start_minute: 0
end_hour: 17
end_minute: 0- id (Required, ID): The
b2500V2 component to control. - generation (Required, int): Must be
2. - timer (Required, int, templatable): Timer index (
0–4). Index0corresponds to Timer 1,1to Timer 2, and so on up to4for Timer 5. - enabled (Optional, boolean, templatable): Whether the timer is enabled.
- output_power (Optional, int, templatable): Timer output power in watts.
- start_hour (Optional, int, templatable): Timer start hour.
- start_minute (Optional, int, templatable): Timer start minute.
- end_hour (Optional, int, templatable): Timer end hour.
- end_minute (Optional, int, templatable): Timer end minute.
Enable or disable adaptive power mode on V2 devices.
on_...:
then:
- b2500.set_adaptive_mode_enabled:
id: b2500_device
generation: 2
enabled: true- id (Required, ID): The
b2500V2 component to control. - generation (Required, int): Must be
2. - enabled (Required, boolean, templatable): Whether to enable (
true) or disable (false) adaptive mode.
Example configuration for an ESP32-S3 with a V2 B2500 device. This shows a representative subset of entities — timers are shown for 1–2 only (3–5 follow the same pattern), and some diagnostic text sensors and binary sensors are omitted for brevity. See the platform sections above for the full list of available entities.
external_components:
- source: github://tomquist/esphome-b2500
components: [b2500]
esphome:
name: b2500-gateway
esp32:
board: esp32-s3-devkitc-1
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
logger:
api:
esp32_ble_tracker:
ble_client:
- mac_address: "AA:BB:CC:DD:EE:FF"
id: my_ble_client
time:
- platform: sntp
id: sntp_time
b2500:
id: b2500_device
generation: 2
on_runtime_info:
then:
- logger.log: "Runtime info updated"
sensor:
- platform: b2500
b2500_id: b2500_device
generation: 2
soc:
name: "Battery SOC"
in1_power:
name: "PV Input 1 Power"
in2_power:
name: "PV Input 2 Power"
in_total_power:
name: "Total Input Power"
out1_power:
name: "Output 1 Power"
out2_power:
name: "Output 2 Power"
out_total_power:
name: "Total Output Power"
capacity:
name: "Remaining Capacity"
temperature_low:
name: "Temperature Low"
temperature_high:
name: "Temperature High"
adaptive_power_out:
name: "Adaptive Output Power"
smart_meter_reading:
name: "Smart Meter Reading"
binary_sensor:
- platform: b2500
b2500_id: b2500_device
generation: 2
wifi_connected:
name: "WiFi Connected"
mqtt_connected:
name: "MQTT Connected"
in1_active:
name: "PV1 Active"
in2_active:
name: "PV2 Active"
out1_active:
name: "Output 1 Active"
out2_active:
name: "Output 2 Active"
smart_meter_connected:
name: "Smart Meter Connected"
switch:
- platform: b2500
b2500_id: b2500_device
generation: 2
adaptive_mode:
name: "Adaptive Mode"
surplus_feed_in:
name: "Surplus Feed-in"
timer1_enabled:
name: "Timer 1 Enabled"
timer2_enabled:
name: "Timer 2 Enabled"
select:
- platform: b2500
b2500_id: b2500_device
generation: 2
charge_mode:
name: "Charge Mode"
number:
- platform: b2500
b2500_id: b2500_device
generation: 2
dod:
name: "Depth of Discharge"
timer1_output_power:
name: "Timer 1 Output Power"
timer2_output_power:
name: "Timer 2 Output Power"
button:
- platform: b2500
b2500_id: b2500_device
generation: 2
reboot:
name: "Reboot"
factory_reset:
name: "Factory Reset"
text_sensor:
- platform: b2500
b2500_id: b2500_device
generation: 2
firmware_version:
name: "Firmware Version"
device_id:
name: "Device ID"
cell_voltage:
name: "Cell Voltage"
datetime:
- platform: b2500
b2500_id: b2500_device
generation: 2
timer1_start:
name: "Timer 1 Start"
timer1_end:
name: "Timer 1 End"
timer2_start:
name: "Timer 2 Start"
timer2_end:
name: "Timer 2 End"To verify the ESPHome component compiles correctly, install the
Python dependencies and run pytest:
pip install esphome pytest
pytest- Thanks to @noone2k for reverse engineering the bluetooth protocol and creating the initial ESPHome config
- Thanks to the ESPHome community for their excellent documentation and tools.
- Thanks to Material-UI for providing the UI components used in this project.