#For $12 and a VM, I can see my car's fuel level on my dashboard

1 messages · Page 1 of 1 (latest)

sharp void
#

I just cobbled this together yesterday, so there are better ways to do many of the sections, but it works! I managed to rig together a little bit of python, a low-spec VM with a USB bluetooth adapter, and HomeAssistant running an MQTT broker to automatically display the fuel levels of our two cars.

I purchased these OBD-II sensors for $12 on Amazon: https://www.amazon.com/dp/B07CP5ZJVQ
I purchased this for another Bluetooth DIY project: https://www.amazon.com/dp/B0DJMN7736, but it just happened to work for this as well. I use this because it has a longer range to reach the driveway/garage from my server. This allowed me to not have to have a second physical device inside the garage listening for the OBD-II sensors.

I spun up a 512 MB single-core vCPU Lubuntu VM on my Proxmox instance (but you could do the same with a Raspberry Pi, as it should be the same steps).

I Bluetooth-paired the VM with the OBD-II sensors via the Desktop GUI, and took note of their MAC addresses. I made a folder at /home/sam/obd to run everything from. I have four Python scripts, and one shell script.

  • /etc/systemd/system/car.service --> service file to run the start_all.sh script at boot
  • start_all.sh --> Kicked off by the service, runs the four .py scripts below
  • listen_for_jeep_fuel.py --> Connects to serial port on OBD-II adapter
  • listen_for_mitsubishi_fuel.py --> "
  • mqtt_jeep.py --> Publishes topic every 10 seconds by reading from the jeep_fuel_level.txt file
  • mqtt_mitsubishi.py --> "

For simplicity, I'll just show the Jeep example (the Mitsubishi is the same with with the rfcomm1 changed to rfcomm0 in the fuel .py, and the .txt filename changed in the mqtt .py).

#

Lubuntu VM

#

listen_for_jeep_fuel.py

#from obd import OBD
import obd
import time
import threading

# Define the polling interval in seconds
POLL_INTERVAL = 1

# Define the command list (you can modify this)
arrCommands = [
    'FUEL_LEVEL'
]

def main():
    returnObj = {}
    while True:
        # Initialize the connection
        connection = obd.OBD(portstr="/dev/rfcomm1", baudrate=9600, fast=False, timeout=30)
        print("connected:", connection.is_connected())
        #print("supported count:", len(connection.supported_commands) if hasattr(connection, "supported_commands") else "unknown")
        #print(connection.supported_commands)

        for name in arrCommands:
            # get command object; skip if not present
            cmd_obj = getattr(obd.commands, name, None)
            if cmd_obj is None:
                print(f"{name}: UNKNOWN COMMAND")
                continue

            res = connection.query(cmd_obj)
            val = None
            if res is None:
                print(f"{name}: NO RESPONSE")
                continue

            if not getattr(res, "is_null", lambda: True)():
                v = res.value
                if hasattr(v, "magnitude"):
                    val = v.magnitude
                    unit = getattr(v, "units", "")
                else:
                    try:
                        val = float(v)
                        unit = ""
                    except Exception:
                        val = str(v)
                        unit = ""

                print(f"{name}: {val} {unit}")
                returnObj[name] = val
                if name == "FUEL_LEVEL":
                    with open("jeep_fuel_level.txt", "w") as f:
                        f.write(f"{val:.2f}")
            else:
                print(f"{name}: NULL / NO DATA")

            # small delay to avoid flooding adapter
            time.sleep(POLL_INTERVAL)

        connection.close()

main()
#

mqtt_jeep.py

Publishes topic every 10 seconds by reading from the jeep_fuel_level.txt file

Replace YOUR_HA_IP_HERE , YOUR_PASSWORD_HERE , MQTT_TOPIC string, and jeep_fuel_level.txt with your own respective values. The topic string can be whatever.

import time
import paho.mqtt.client as mqtt
from flask import Flask

app = Flask(__name__)

# MQTT broker configuration
MQTT_BROKER = "YOUR_HA_IP_HERE"  # e.g., 192.168.1.100
MQTT_PORT = 1883
MQTT_USERNAME = "sam"  # if authentication is enabled
MQTT_PASSWORD = "YOUR_PASSWORD_HERE"  # if authentication is enabled
MQTT_TOPIC = "home-assistant/cars/jeep/obd2/fuel_level" 

# Initialize MQTT client
client = mqtt.Client()
client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD)
client.connect(MQTT_BROKER, MQTT_PORT, 60)

def publish_data():
    """Function to publish data to the MQTT broker."""
    # Replace this with your actual data source
    #data = "Sample data from Flask server at " + time.strftime("%Y-%m-%d %H:%M:%S")
    data = open("jeep_fuel_level.txt").read()
    client.publish(MQTT_TOPIC, data)
    print(f"Published: {data}")

# Schedule the function to run every N seconds (e.g., every 10 seconds)
N = 10  # seconds
while True:
    publish_data()
    time.sleep(N)
#

start_all.sh

  • Replace the MAC addresses with your device MACs
  • Replace /home/sam/obd with your directory
#!/bin/bash

# Bind OBD2 sensors to RFCOMM ports
sudo unbind /dev/rfcomm0
sudo unbind /dev/rfcomm1
sudo rfcomm bind /dev/rfcomm0 66:1E:32:8D:43:0A
sudo rfcomm bind /dev/rfcomm1 66:1E:32:8D:5D:80

# Start all scripts in background and wait so the service stays alive
exec /home/sam/.venv/obd/bin/python /home/sam/obd/mqtt_mitsubishi.py &
exec /home/sam/.venv/obd/bin/python /home/sam/obd/mqtt_jeep.py &
exec /home/sam/.venv/obd/bin/python /home/sam/obd/listen_for_jeep_fuel.py &
exec /home/sam/.venv/obd/bin/python /home/sam/obd/listen_for_mitsubishi_fuel.py &

wait
#

/etc/systemd/system/car.service

  • Replace /home/sam/obd with your directory
  • I probably shouldn't run as root, but I just wanted to DIY this quick
[Unit]
Description=Start 4 Python scripts
After=network.target

[Service]
Type=simple
User=root
WorkingDirectory=/home/sam/obd
ExecStart=/home/sam/obd/start_all.sh
Restart=on-failure
RestartSec=5
# Optional: capture logs to journal
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

Enable the service:

sudo systemctl daemon-reload
sudo systemctl enable car.service
sudo systemctl start car.service

You can check logs with:

sudo systemctl status car.service
sudo journalctl -u car.service -f
#

In Home Assistant

configuration.yaml:

mqtt:
    - sensor:
        - name: "Jeep Fuel Level"
          state_topic: "home-assistant/cars/jeep/obd2/fuel_level"
          unit_of_measurement: "%"
          device_class: "battery"
          unique_id: "jeep_fuel_level"
#
type: gauge
entity: sensor.jeep_fuel_level
unit: "%"
severity:
  green: 40
  yellow: 20
  red: 0
needle: true
grid_options:
  columns: 6
  rows: auto
#

Reading from a $12 Bluetooth OBD-II sensor to show fuel levels

#

Reading from a $12 Bluetooth OBD-II (OBD2) sensor to show fuel levels without using the Torque app

sharp void
#

For $12 and a VM, I can see my car's fuel level on my dashboard

dry oar
#

I'll pay for something like this ready to use 🙂

wooden cedar
#

Yo, this is rad! And I have pretty much everything I would need, already in place. I have a KONNWEI bluetooth OBD (based on an ELM327 chip) in the car, and my home assistant is already running in a VM under Proxmox, and has a USB bluetooth adapter! My car is a Kia Soul EV, so I'm interested in the battery state and stuff like that, but that's just the details.

I was planning on over-complicating it by reading the data from Note-RED on a Pi, then sending it to Home Assistant.

Thank you for sharing this, I'm definitely gonna refer to it as I work on my own project!

wise egret
#

And is this project possible to use with the car sending signal via wifi?

dry oar
primal briar
#

Will this only work with VM, new to home assistant but mechanic to trade and intrested in this. My home assistant running on what was a faulty hp laptop for now till I learn more. Ty in advance

sharp void
#

Ran into a couple of bugs since this, but they should be easy to solve

#

My check-engine came on again (don't buy a Jeep Wrangler pepeASmile ), and I got it to read the codes for it.

sharp void
# dry oar I'll pay for something like this ready to use 🙂
#

An ESPHome script might be the way to go for what I did, I just wonder how well the bluetooth range on one is. The tricky part is getting it to run fast enough to pick up the sensor of either car in the short time that we're pulling into the driveway.

sharp void