eigger
(eigger)
May 22, 2026, 11:48am
1
Hi everyone,
I've put together a custom ESPHome component that allows you to read car data using a BLE ELM327 (OBD2) scanner.
You can find the code and the README with configuration details here:
Here is the YAML configuration from my actual setup:
Any shared extended PIDs would be greatly appreciated!
I recently built a small project for my Chevy Colorado that displays real-time vehicle data using an OBD adapter and an M5Stack display. I also integrated external BLE temperature/humidity sensors so I can monitor both the passenger cabin and the truck bed environment.
Hardware Used
M5Stack Tab5 and Atom for the main display (ble)
Jaalee BLE temperature & humidity sensors
Vgate vLinker MC+ OBD-II adapter
Wi-Fi/LTE hotspot with VPN connection to Home Assistant
[2022110829805]
[Jaalee-JHT-iB…
3 Likes
eigger
(eigger)
May 24, 2026, 12:09pm
3
Anyway, since it communicates via OBD scanner commands, all PIDs supported by the vehicle should be available.
eigger
(eigger)
May 24, 2026, 10:34pm
5
First, you need to connect to the OBD scanner, so you will need its MAC address and the operating UUID. You can find them using an app called nRF Connect. This is my setup. For the full configuration, please check the URL.
ble_client:
- mac_address: ${mac_vlinker}
id: obd_client
ble_elm327:
id: obd_elm
ble_client_id: obd_client
service_uuid: "18F0"
rx_char_uuid: "2AF0"
tx_char_uuid: "2AF1"
init_commands:
- "ATZ"
- "ATE0"
- "ATL0"
- "ATS0"
- "ATH0"
- "ATSP6"
tx_delay: 100
The basic standard PIDs can be configured as follows:
sensor:
- platform: ble_elm327
id: "engine_run_time"
name: "Engine Run Time"
preset: run_time
update_interval: 10s
To configure the PIDs manually, you can define the mode, pid, and formula yourself as follows:
sensor:
- platform: ble_elm327
name: "Intake Air Temperature"
pid: "0F"
mode: "01"
update_interval: 10s
formula: "return a - 40.0f;"
unit_of_measurement: "°C"
device_class: temperature
state_class: measurement
eigger
(eigger)
May 25, 2026, 9:29am
7
It might need some testing, but I think you can set it up like this."
- platform: ble_elm327
name: "Peugeot e-208 SOH"
pid: "D860"
mode: "22"
update_interval: 10s
formula: "return ((int16_t)((a << 8) | b)) / 16.0f;" # or ((int16_t)((b << 8) | c)) / 16.0f;"
unit_of_measurement: "%"
accuracy_decimals: 1
state_class: measurement
eigger
(eigger)
May 27, 2026, 10:55pm
9
You can add it as shown in the init_commands below. You need to add all of the init_commands. Otherwise, parsing might fail.
ble_elm327:
id: obd_elm
ble_client_id: obd_client
service_uuid: "18F0"
rx_char_uuid: "2AF0"
tx_char_uuid: "2AF1"
init_commands:
- "ATZ"
- "ATE0"
- "ATL0"
- "ATS0"
- "ATH0"
- "ATSP6"
- "ATSH6B4"
tx_delay: 50
eigger
(eigger)
May 28, 2026, 1:38am
11
I'll look into enabling separate commands for each PID.
eigger
(eigger)
May 28, 2026, 1:53am
12
By referring to this link, you can send a separate pre-command for each PID.
I tested it and it's working. Thank you.
1 Like
eigger
(eigger)
May 30, 2026, 8:17am
16
Could you share a working PID YAML configuration? I'd like to add it to example.
platform: ble_elm327
name: "SOH"
ble_elm327_id: obd_elm
mode: "22"
pid: "D860"
pre_commands:
"ATSH 6B4"
update_interval: 30s
formula: |-
return ((b * 256.0f) + c) / 16.0f;
unit_of_measurement: "%"
accuracy_decimals: 1
state_class: measurement
platform: ble_elm327
ble_elm327_id: obd_elm
name: "SOC"
pre_commands:
"ATSH 6B4"
mode: "22"
pid: "D410"
update_interval: 30s
formula: |-
return ((a * 256.0f) + b) / 512.0f;
unit_of_measurement: "%"
accuracy_decimals: 1
state_class: measurement
platform: ble_elm327
name: "HV Voltage"
mode: "22"
pid: "D815"
pre_commands:
"ATSH 6B4"
update_interval: 30s
formula: |-
return ((a * 256.0f) + b) / 16.0f;
unit_of_measurement: "V"
accuracy_decimals: 1
state_class: measurement
device_class: voltage
platform: ble_elm327
name: "Odometro"
ble_elm327_id: obd_elm
mode: "22"
pid: "D49C"
pre_commands:
"ATSH6A6"
update_interval: 35s
formula: |-
return ((b * 65536.0f) + (c * 256.0f) + d);
unit_of_measurement: "km"
accuracy_decimals: 0
state_class: total_increasing
It's working on a 2021 Citroen E_Berlingo, which is the same as a Peugeot E208.
I have more PIDs that I'm going to test.
eigger
(eigger)
May 30, 2026, 9:29am
18
Thank you. I'll add this to my GitHub README.