← Back to Garden
budding ·
iot architecture mqtt timescaledb

TSI-Telemetry Architecture

System Overview

┌─────────────┐    BLE    ┌─────────────┐   WiFi    ┌─────────────┐
│   Car ECU   │◄────────►│    ESP32    │◄────────►│Phone Hotspot│
│  (OBD-II)   │          │  (firmware) │           └──────┬──────┘
└─────────────┘          └─────────────┘                  │
                                                      Internet
                                                          │
                                                  ┌───────▼───────┐
                                                  │  HiveMQ Cloud │
                                                  │ (MQTT Broker) │
                                                  └───────┬───────┘
                                                          │
                                                      Internet
                                                          │
                         ┌────────────────────────────────┴───┐
                         │         Mac Mini (Home)            │
                         │                                    │
                         │  ┌──────────────┐  ┌───────────┐  │
                         │  │ Python Bridge│─►│TimescaleDB│  │
                         │  │   (MQTT sub) │  │ (Docker)  │  │
                         │  └──────────────┘  └─────┬─────┘  │
                         │                          │        │
                         │                    ┌─────▼─────┐  │
                         │                    │  Grafana  │  │
                         │                    │(dashboard)│  │
                         │                    └───────────┘  │
                         └───────────────────────────────────┘

Why Cloud MQTT Broker?

The ESP32 connects to your phone's hotspot while driving. Your Mac Mini is at home behind NAT. They can't reach each other directly.

Solution: Use HiveMQ Cloud as an intermediary:

  • ESP32 publishes to cloud broker
  • Mac Mini bridge subscribes to cloud broker
  • No NAT/firewall issues
  • Free tier is sufficient

Data Flow

  1. Car ECU exposes data via OBD-II port
  2. ELM327 adapter translates OBD-II protocol to Bluetooth LE
  3. ESP32 connects to ELM327, requests PIDs, parses responses
  4. ESP32 connects to phone hotspot WiFi
  5. ESP32 publishes telemetry to HiveMQ Cloud topic car/telemetry
  6. Python Bridge (on Mac Mini) subscribes to HiveMQ Cloud
  7. Bridge writes data to TimescaleDB
  8. Grafana queries TimescaleDB, displays real-time dashboard

Why This Stack?

Why MQTT?

  • Lightweight protocol designed for IoT
  • Low bandwidth overhead
  • Pub/Sub model decouples producers and consumers
  • QoS levels for reliability
  • Works well over unreliable mobile connections

Why TimescaleDB over InfluxDB?

We switched from InfluxDB to TimescaleDB because:

  • Built on PostgreSQL (familiar SQL syntax)
  • Easier setup and querying
  • Better for complex analytics later
  • Hypertables handle time-series optimization automatically
  • Can mix relational and time-series data

Why HiveMQ Cloud over local Mosquitto?

  • ESP32 can't reach home network from mobile hotspot
  • No port forwarding or VPN setup needed
  • Free tier (10 GB/month) is plenty for telemetry
  • TLS encryption included
  • Reliable cloud infrastructure

Components

ESP32 Firmware Modules

Module Responsibility
BLEManager BLE connection to ELM327
OBDParser Parse OBD-II responses
CarData Data structure for telemetry
DisplayManager Serial output formatting
Config Configuration constants
WiFiManager (TODO) WiFi connection
MQTTManager (TODO) MQTT publishing to HiveMQ

Server Components

Component Port Purpose
TimescaleDB (Docker) 5433 Time-series database
Grafana 3000 Visualization
Python Bridge - MQTT to TimescaleDB
HiveMQ Cloud 8883 Cloud MQTT broker

OBD-II Protocol

Request Format

01 0C\r     <- Request PID 0C (RPM)

Response Format

41 0C 1A 2B  <- Response
│  │  │  │
│  │  └──┴── Data bytes (A=0x1A, B=0x2B)
│  └──────── PID (0C = RPM)
└─────────── Mode 41 = positive response to mode 01

PID Conversion Formulas

PID Name Formula Unit
0x0C RPM (A*256 + B) / 4 rpm
0x0D Speed A km/h
0x05 Coolant Temp A - 40 °C
0x0F Intake Temp A - 40 °C
0x11 Throttle A * 100 / 255 %
0x04 Engine Load A * 100 / 255 %
0x0B MAP A kPa
0x2F Fuel Level A * 100 / 255 %
0x0E Timing Advance A / 2 - 64 degrees
0x42 Battery Voltage (A*256 + B) / 1000 V

Network Topology

┌─────────────────────────────────────────────────────────────────┐
│                         WHILE DRIVING                           │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   Car                     Phone                    Cloud        │
│  ┌─────┐                ┌───────┐              ┌─────────┐     │
│  │ESP32│───WiFi────────►│Hotspot│───Cellular──►│ HiveMQ  │     │
│  └─────┘                └───────┘              │  Cloud  │     │
│                                                └────┬────┘     │
│                                                     │          │
├─────────────────────────────────────────────────────┼──────────┤
│                           HOME                      │          │
├─────────────────────────────────────────────────────┼──────────┤
│                                                     │          │
│                                                ┌────▼────┐     │
│                                                │ Bridge  │     │
│                                                └────┬────┘     │
│                                                     │          │
│                                                ┌────▼────┐     │
│                                                │Timescale│     │
│                                                └────┬────┘     │
│                                                     │          │
│                                                ┌────▼────┐     │
│                                                │ Grafana │     │
│                                                └─────────┘     │
└─────────────────────────────────────────────────────────────────┘