I can now read the values. How can I send the data to my MQTT broker?
With these commands i can read out on my Samsung Galaxy S10 the SoC, the range, the charging status, the odometer and the charging power. But I don’t now how to pass the values to the MQTT broker.
adb shell am force-stop com.byd.bydautolink
adb shell monkey -p com.byd.bydautolink -c android.intent.category.LAUNCHER 1
sleep 20
adb exec-out screencap -p > screenshot.png # Take a screenshot
convert screenshot.png -crop 90x50+280+260 cropped_soc.png # Crop the screenshot
tesseract cropped_soc.png stdout -c tessedit_char_whitelist=0123456789 --psm 6
sleep 5
convert screenshot.png -crop 90x50+60+260 cropped_range.png # Crop the screenshot
tesseract cropped_range.png stdout -c tessedit_char_whitelist=0123456789 --psm 6
sleep 5
convert screenshot.png -crop 160x50+570+1120 cropped_charging.png # Crop the screenshot
tesseract cropped_charging.png stdout -c tessedit_char_whitelist=0123456789 --psm 6
sleep 5
convert screenshot.png -crop 100x50+730+1120 cropped_power.png # Crop the screenshot
tesseract cropped_power.png stdout -c tessedit_char_whitelist=0123456789. --psm 6
perfect!
to pass things to mqtt please google the information. I guess there are many tutorials to pass data from bash to mqtt
ChatGPT is also very helpful!
This is my finished script.
#!/bin/bash
BROKER="192.168.1.40"
TOPIC_BASE="auto/byd"
USER="username"
PASSWORD="password"
while true; do
adb shell am force-stop com.byd.bydautolink
adb shell monkey -p com.byd.bydautolink -c android.intent.category.LAUNCHER 1
sleep 20
adb exec-out screencap -p > screenshot.png
# SOC
convert screenshot.png -crop 90x50+280+260 cropped_soc.png
SOC=$(tesseract cropped_soc.png stdout -c tessedit_char_whitelist=0123456789 --psm 6 | tr -dc '0-9')
mosquitto_pub -h "$BROKER" -u "$USER" -P "$PASSWORD" -t "$TOPIC_BASE/soc" -m "$SOC"
# Reichweite
convert screenshot.png -crop 90x50+60+260 cropped_range.png
RANGE=$(tesseract cropped_range.png stdout -c tessedit_char_whitelist=0123456789 --psm 6 | tr -dc '0-9')
mosquitto_pub -h "$BROKER" -u "$USER" -P "$PASSWORD" -t "$TOPIC_BASE/range" -m "$RANGE"
# Restliche Ladezeit (hh:mm)
convert screenshot.png -crop 160x50+570+1120 cropped_remaining_time.png
RAW_TIME=$(tesseract cropped_remaining_time.png stdout -c tessedit_char_whitelist=0123456789hm --psm 6)
CLEAN_TIME=$(echo "$RAW_TIME" | tr -d '[:space:]')
if [[ "$CLEAN_TIME" =~ ^([0-9]+)h([0-9]+)min$ ]]; then
HOURS="${BASH_REMATCH[1]}"
MINS="${BASH_REMATCH[2]}"
REMAINING_TIME=$(printf "%02d:%02d" "$HOURS" "$MINS")
elif [[ "$CLEAN_TIME" =~ ^([0-9]+)h$ ]]; then
HOURS="${BASH_REMATCH[1]}"
REMAINING_TIME=$(printf "%02d:00" "$HOURS")
elif [[ "$CLEAN_TIME" =~ ^([0-9]+)min$ ]]; then
MINS="${BASH_REMATCH[1]}"
REMAINING_TIME=$(printf "00:%02d" "$MINS")
else
REMAINING_TIME="$RAW_TIME"
fi
mosquitto_pub -h "$BROKER" -u "$USER" -P "$PASSWORD" -t "$TOPIC_BASE/remaining_time" -m "$REMAINING_TIME"
# Ladeleistung (kW)
convert screenshot.png -crop 100x50+730+1120 cropped_power.png
POWER=$(tesseract cropped_power.png stdout -c tessedit_char_whitelist=0123456789. --psm 6 | tr -dc '0-9.')
mosquitto_pub -h "$BROKER" -u "$USER" -P "$PASSWORD" -t "$TOPIC_BASE/power" -m "$POWER"
# Odometer
adb shell input tap 900 2100
sleep 20
adb exec-out screencap -p > screenshot_me.png
convert screenshot_me.png -crop 175x50+100+880 cropped_odo.png
ODO=$(tesseract cropped_odo.png stdout -c tessedit_char_whitelist=0123456789 --psm 6 | tr -dc '0-9')
mosquitto_pub -h "$BROKER" -u "$USER" -P "$PASSWORD" -t "$TOPIC_BASE/odo" -m "$ODO"
# Warten bis zur nächsten Minute
sleep 60
done
Looks good. I’ll not test it, because my solution using PHP and Loxone works well for me.
found another solution:
adb shell uiautomator dump /sdcard/view.xml >/dev/null 2>&1
adb exec-out cat /sdcard/view.xml
you get a full xml dump of the screen and can parse it to get the needed values.
How do you know you can trust evlinkha? I mean, I’m not saying it is harmful or that its owner has is a bad actor, but giving access to all my EV data to a third party that will keep that data on the cloud is not easy to accept for me. If evlinkha is compromised, bad actors can have access to my EV usage data and location.
Actually, the same applies to enode. I’m not comfortable sharing my data with a third-party. But at least enode is well-established and has good reputation.
Ideally we should be able to link our EV to HA directly.
How do you know you can trust anyone? I mean I tried it, but I’m not going to use it long term. I’m just going to keep using my bluetooth reading of the OBDLink CX
Let’s for a moment consider the fact that we’re driving Chinese cars that already capture a lot of telemetry about us, let alone are already listening for every word we say, just in case we say “hi BYD”. ![]()
that is true. still, the less vulnerable points the better.
I don’t disagree with your point though - I would much rather be able to connect direct to BYD as that’s where the data is, instead of via someone’s service which is utilising another service.
Look at this code. It works perfect for me. The BYD app runs on a badly scratched Samsung Galaxy S10. At least now I have a use for it.
import json
import subprocess
import time
import xml.etree.ElementTree as ET
import paho.mqtt.client as mqtt
# ===== MQTT Einstellungen =====
MQTT_BROKER = "192.168.1.40"
MQTT_PORT = 1883
MQTT_USER = "user"
MQTT_PASS = "password"
MQTT_TOPIC_BASE = "byd/app"
# ===== XML Mapping =====
XML_MAP = {
"com.byd.bydautolink:id/h_km_tv": "range_km",
"com.byd.bydautolink:id/tv_batter_percentage": "battery_soc",
"com.byd.bydautolink:id/tv_charging_tip": "charging_tip",
"com.byd.bydautolink:id/tv_banner": "warning",
"com.byd.bydautolink:id/car_inner_temperature": "cabin_temp",
"com.byd.bydautolink:id/tem_tv": "ac_set_temp",
"com.byd.bydautolink:id/h_car_name_tv": "car_status",
"com.byd.bydautolink:id/tv_update_time": "last_update",
"com.byd.bydautolink:id/tire_tv_01": "tire_pressure_fl",
"com.byd.bydautolink:id/tire_tv_02": "tire_pressure_rl",
"com.byd.bydautolink:id/tire_tv_03": "tire_pressure_fr",
"com.byd.bydautolink:id/tire_tv_04": "tire_pressure_rr",
"com.byd.bydautolink:id/iv_value_front_hood": "front_hood",
"com.byd.bydautolink:id/iv_value_door": "door",
"com.byd.bydautolink:id/iv_value_window": "window",
"com.byd.bydautolink:id/iv_value_sunroof": "sunroof",
"com.byd.bydautolink:id/iv_value_trunk": "trunk",
"com.byd.bydautolink:id/tv_value_mileage": "odometer",
"com.byd.bydautolink:id/tv_recent_energy_value": "recent_energy_value",
"com.byd.bydautolink:id/tv_total_energy_value": "total_energy_value",
"com.byd.bydautolink:id/tv_tv_car_state_value": "car_state_value",
"com.byd.bydautolink:id/tv_car_travel_state_title": "car_travel_state_title",
}
# ===== ADB Aktionen =====
ACTIONS = {
"refresh": ("input tap 546 370", 2),
"car_status": ("input tap 284 1131", 1),
"car_position": ("input tap 854 1822", 1),
"navigation": ("input tap 726 1983", 1),
"map_back": ("input tap 92 242", 1),
"finish": ("input tap 84 170", 1),
"swipe_up": ("input swipe 500 1500 500 500 500", 2),
"swipe_down": ("input swipe 500 500 500 1500 500", 2),
"stop_google_maps": ("am force-stop com.google.android.apps.maps", 2),
}
# ===== MQTT Setup =====
def connect_mqtt():
client = mqtt.Client()
client.username_pw_set(MQTT_USER, MQTT_PASS)
client.on_disconnect = lambda c, u, rc: print("⚠️ MQTT getrennt, versuche Reconnect...")
client.connect(MQTT_BROKER, MQTT_PORT, 60)
client.loop_start()
return client
client = connect_mqtt()
# ===== ADB Hilfsfunktionen =====
def adb_command(cmd: str, wait: float = 1.0):
subprocess.run(["adb", "shell"] + cmd.split(), check=False)
if wait:
time.sleep(wait)
def perform(action: str):
if action not in ACTIONS:
print(f"❌ Unbekannte Aktion: {action}")
return
cmd, wait = ACTIONS[action]
adb_command(cmd, wait)
def get_ui_dump(filename="window_dump.xml"):
remote_file = f"/sdcard/{filename}"
adb_command(f"uiautomator dump {remote_file}", 1)
subprocess.run(["adb", "pull", remote_file, filename],
check=False,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL)
return filename
# ===== XML Parsing =====
def extract_values(xml_file: str):
tree = ET.parse(xml_file)
root = tree.getroot()
values = {}
for node in root.iter("node"):
rid = node.attrib.get("resource-id", "")
text = node.attrib.get("text", "")
bounds = node.attrib.get("bounds", "")
cls = node.attrib.get("class", "")
if not text:
continue
if rid in XML_MAP:
values[XML_MAP[rid]] = text
elif cls == "android.widget.TextView" and "[83,153]" in bounds:
values["car_position"] = text
return values
# ===== MQTT Publish Funktionen =====
def publish_car_position(raw_coords):
try:
lat, lon = map(str.strip, raw_coords.split(","))
payload = {
"latitude": float(lat),
"longitude": float(lon),
"gps_accuracy": 10,
"status": "driving"
}
client.publish(f"{MQTT_TOPIC_BASE}/location", json.dumps(payload))
print(f"MQTT publish -> {payload}")
except Exception as e:
print(f"Fehler beim Verarbeiten der Koordinaten: {e}")
def publish_values(values: dict):
if not values:
print("⚠️ Keine Werte gefunden.")
return
# Einzelne Sensoren
for key, val in values.items():
topic = f"{MQTT_TOPIC_BASE}/{key}"
client.publish(topic, val)
print(f"➡️ Publish {topic} -> {val}")
# ===== Hauptschleife =====
def main_loop():
while True:
all_values = {}
# Reihenfolge der Dumps/Aktionen
dumps_sequence = [
("window_dump_1.xml", []),
("window_dump_2.xml", ["swipe_up", "car_status"]),
("window_dump_3.xml", ["swipe_up"]),
("window_dump_4.xml", ["finish", "swipe_down", "car_position"]),
("window_dump_5.xml", ["navigation"]),
]
for filename, actions in dumps_sequence:
for action in actions:
perform(action)
get_ui_dump(filename)
all_values.update(extract_values(filename))
# Position separat publishen
if "car_position" in all_values:
publish_car_position(all_values["car_position"])
# Alle Sensorwerte publishen
publish_values(all_values)
# Google Maps stoppen & zurück
perform("stop_google_maps")
perform("map_back")
time.sleep(60)
if __name__ == "__main__":
try:
main_loop()
except KeyboardInterrupt:
print("🚪 Script beendet.")
client.loop_stop()
client.disconnect()
Looks like these Nissan Leaf owners are pursuing something along the lines of connecting to ESPHome to BLE dongle. Nissan Leaf via LeLink 2 (ELM327) BLE - ESPHome
@dgaust has already done this for the Seal, and I have extended it to an Atto 3 and iCar Pro 2S OBD2 dongle. It works very well.
Hi, I’m sure the best route would be to have an app installed in the card that would send the car’s sensor data to Home Assistant.
This app exposes a lot of features of the byd car to a mobile app:
https://electro.app.br/
It’s still in beta, but I gives an idea of what is possible. Just wish there was something simple (an open source) that would allow just to send data to hassio.
Installed the app. I think it uses “Debug mode when USB is connected”/“Wireless adb” to get info from the car.
https://electro.app.br/usb
The app is also running when the car is off, so you can get notification if a door is open.
This looks interesting, will try it out. Is there anyway to connect this to home assistant?
Not yet, unfortunately.
Oh wow! Been looking for a way to bring my BYD into HA for 2 years. Can’t believe how easy it was in the end. Thanks.

