Streams BMW CarData MQTT events into a PostgreSQL table. Minimal, single-script pipeline.
-
Reads auth and identifiers from a token JSON file.
-
Subscribes to
customer.streaming-cardata.bmwgroup.com:9000on topic<gcid>/<vin>. -
Extracts
.datafrom each MQTT message. -
Inserts each JSON payload into PostgreSQL via
stdin2sql.php:INSERT INTO <table> (<payload_col>) VALUES ($1::JSONB) RETURNING <id_col>;
-
Runs forever and reconnects on failure.
jq- PostgreSQL server
- mqtt-sub
- stdin2sql.php
- bmw-token-manager
- OPTIONAL:
/opt/amp-bash-commons/shell-util.sh(or removeparseCommandlineArgumentsandparseCommandlineArguments)
Create a table with a JSONB payload and an id column. Example:
CREATE TABLE bmw_mqtt (
id BIGSERIAL PRIMARY KEY,
ts BIGINT NOT NULL DEFAULT (EXTRACT(EPOCH FROM clock_timestamp())*1000000)::BIGINT,
payload JSONB NOT NULL
);Path given with -t/--token-file.
{
"gcid": "XXXXXXXXXXXXXXXXXXXXXX",
"token_type": "Bearer",
"access_token": "XXXXXXXXXXXXXXXXXXXXXX",
"refresh_token": "XXXXXXXXXXXXXXXXXXXXXX",
"scope": "openid cardata:streaming:read authenticate_user",
"expires_in": 3599,
"id_token": "XXXXXXXXXXXXXXXXXXXXXX",
"fetched_at": 1234567890,
"expires_at": 1234567890,
"client_id": "XXXXXXXXXXXXXXXXXXXXXX",
"vin": "XXXXXXXXXXXXXXXXXXXXXX"
}- gcid: BMW Group Customer ID used as MQTT username.
- token_type: Usually
"Bearer". - access_token: Short-lived OAuth access token.
- refresh_token: Long-lived token used to obtain new
id_token. - scope: Granted scopes string. Must contain
cardata:streaming:read. - expires_in: Seconds until expiry as returned by the last token endpoint call.
- id_token: Used as MQTT password.
- fetched_at: Unix epoch when the last refresh was fetched.
- expires_at: Absolute Unix epoch expiry time.
- client_id: OAuth client ID used for refresh.
- vin: Vehicle identifier.
./bmw2sql.sh \
--token-file token.json \
--table bmw_mqtt \
--payload payload \
--id idShort forms:
-t, --token-file FILEtoken JSON path-b, --table NAMEtarget table (defaultbmw_mqtt)-p, --payload NAMEJSONB column (defaultpayload)-i, --id NAMEid column returned (defaultid)
You can also set env vars instead of flags:
BMW_TOKEN_FILE,BMW_TABLE,BMW_PAYLOAD_COLUMN,BMW_ID_COLUMN- All libpq environment variables are also honored (
PGUSER,PGDATABASE, ...)
- Topic is
<gcid>/<vin>. Credentials:--username $gcid,--password $id_token. - Only the
.datafield of each message is stored. - The script prints a timestamp at each reconnect.
- Ensure the token file is protected:
chmod 600 token.json.