@eiguudewie/node-red-contrib-bmw-cardata 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +18 -0
- package/README.md +274 -0
- package/bmw-cardata-config.html +603 -0
- package/bmw-cardata-config.js +1054 -0
- package/bmw-cardata-query.html +146 -0
- package/bmw-cardata-query.js +144 -0
- package/bmw-cardata-soc.html +98 -0
- package/bmw-cardata-soc.js +190 -0
- package/package.json +39 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 mm
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
|
6
|
+
associated documentation files (the "Software"), to deal in the Software without restriction, including
|
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
|
|
9
|
+
following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial
|
|
12
|
+
portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
|
15
|
+
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
|
16
|
+
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
18
|
+
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
# @eiguudewie/node-red-contrib-bmw-cardata
|
|
2
|
+
|
|
3
|
+
Node-RED integration for the **BMW CarData REST API**. Reads vehicle telemetry such as State of Charge (SoC) via OAuth2 and forwards it to other systems.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
1. [Overview](#overview)
|
|
10
|
+
2. [Prerequisites](#prerequisites)
|
|
11
|
+
3. [BMW CarData Portal – Setup](#bmw-cardata-portal--setup)
|
|
12
|
+
4. [Installation](#installation)
|
|
13
|
+
5. [Configuration](#configuration)
|
|
14
|
+
6. [Nodes](#nodes)
|
|
15
|
+
- [bmw-cardata-config](#bmw-cardata-config)
|
|
16
|
+
- [bmw-cardata-soc](#bmw-cardata-soc)
|
|
17
|
+
- [bmw-cardata-query](#bmw-cardata-query)
|
|
18
|
+
7. [Example Flow](#example-flow)
|
|
19
|
+
8. [Rate Limit](#rate-limit)
|
|
20
|
+
9. [API Endpoints](#api-endpoints)
|
|
21
|
+
10. [License](#license)
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Overview
|
|
26
|
+
|
|
27
|
+
This package provides three Node-RED nodes for the BMW CarData REST API:
|
|
28
|
+
|
|
29
|
+
- **bmw-cardata-config** – Central config node. Manages OAuth2 authentication (Device Flow with PKCE), automatic token refresh, and container lifecycle. Shared by all other nodes.
|
|
30
|
+
- **bmw-cardata-soc** – Reads the battery State of Charge (SoC). Simple, fixed datapoints, output as integer or full object.
|
|
31
|
+
- **bmw-cardata-query** – Generic query node. Configurable datapoints and container name, returns the full raw telemetry response.
|
|
32
|
+
|
|
33
|
+
Authentication is handled once via a browser-based BMW account confirmation. Tokens are stored and refreshed automatically. Container management (required by the BMW API) is fully automatic and cached locally.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Prerequisites
|
|
38
|
+
|
|
39
|
+
- Node-RED >= 3.0
|
|
40
|
+
- Node.js >= 16
|
|
41
|
+
- BMW vehicle with an active ConnectedDrive account
|
|
42
|
+
- Registered BMW CarData API client (see below)
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## BMW CarData Portal – Setup
|
|
47
|
+
|
|
48
|
+
Before using the nodes you need to create an API client in the BMW CarData Portal. This is a one-time step.
|
|
49
|
+
|
|
50
|
+
### 1. Open the BMW CarData Portal
|
|
51
|
+
|
|
52
|
+
→ [https://bmw-cardata.bmwgroup.com/customer](https://bmw-cardata.bmwgroup.com/customer)
|
|
53
|
+
|
|
54
|
+
Sign in with your BMW ConnectedDrive account.
|
|
55
|
+
|
|
56
|
+
### 2. Create a Client ID
|
|
57
|
+
|
|
58
|
+
1. Navigate to **"API Clients"** → **"Create CarData Client"**
|
|
59
|
+
2. Enter a name (e.g. `HomeAutomation`)
|
|
60
|
+
3. Select the scope **`cardata:api:read`**
|
|
61
|
+
4. Confirm the creation
|
|
62
|
+
5. Copy the displayed **Client ID** (format: `XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX`)
|
|
63
|
+
|
|
64
|
+
> ⚠️ The Client ID is only shown in full once – save it immediately.
|
|
65
|
+
|
|
66
|
+
### 3. Find your VIN
|
|
67
|
+
|
|
68
|
+
The **VIN (Vehicle Identification Number)** is 17 characters long. Where to find it:
|
|
69
|
+
|
|
70
|
+
- Dashboard (base of the windshield, visible from outside) or driver's door jamb sticker
|
|
71
|
+
- Vehicle registration or title document
|
|
72
|
+
- BMW ConnectedDrive app or online portal
|
|
73
|
+
- Vehicle registration certificate (Zulassungsbescheinigung Teil I, field E) — Germany
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Installation
|
|
78
|
+
|
|
79
|
+
Via the Node-RED Palette Manager: search for **`@eiguudewie/node-red-contrib-bmw-cardata`** and click Install.
|
|
80
|
+
|
|
81
|
+
Via npm:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
cd ~/.node-red
|
|
85
|
+
npm install @eiguudewie/node-red-contrib-bmw-cardata
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Then restart Node-RED:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
sudo systemctl restart nodered
|
|
92
|
+
# or
|
|
93
|
+
node-red
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Configuration
|
|
99
|
+
|
|
100
|
+
All nodes share a single **bmw-cardata-config** node that holds credentials and manages the API session. Configure it once and reuse it across all BMW nodes in your flow.
|
|
101
|
+
|
|
102
|
+
### Authentication (OAuth2 Device Flow with PKCE)
|
|
103
|
+
|
|
104
|
+
1. Open the config node, enter **Client ID** and **VIN**, then save
|
|
105
|
+
2. Click **"Authenticate now"**
|
|
106
|
+
3. Open the displayed link in your browser and enter the **user code**
|
|
107
|
+
4. Sign in with your BMW account and confirm access
|
|
108
|
+
5. Node-RED detects the confirmation automatically and stores the token
|
|
109
|
+
|
|
110
|
+
The access token is renewed automatically using the stored refresh token. The session is persisted in `~/.node-red/bmw-cardata-session-{nodeId}.json`.
|
|
111
|
+
|
|
112
|
+
### Containers
|
|
113
|
+
|
|
114
|
+
The BMW CarData API requires a **container** that declares which datapoints to return. The plugin manages containers automatically:
|
|
115
|
+
|
|
116
|
+
- On first use, a suitable ACTIVE container is located or a new one is created
|
|
117
|
+
- Container keys and IDs are cached locally — subsequent requests need no extra API calls
|
|
118
|
+
- The **Inspect containers** button in the config node shows all containers and their cached keys
|
|
119
|
+
- Individual containers can be deleted from the UI
|
|
120
|
+
- **Clear container cache** forces a fresh lookup on the next request
|
|
121
|
+
|
|
122
|
+
Default keys used when no custom keys are configured:
|
|
123
|
+
|
|
124
|
+
| Key | Description |
|
|
125
|
+
|-----|-------------|
|
|
126
|
+
| `vehicle.drivetrain.batteryManagement.header` | State of Charge (%) |
|
|
127
|
+
| `vehicle.drivetrain.electricEngine.charging.status` | Charging status |
|
|
128
|
+
| `vehicle.powertrain.electric.battery.charging.power` | Charging power (kW) |
|
|
129
|
+
|
|
130
|
+
### API Call Counter
|
|
131
|
+
|
|
132
|
+
The config node tracks every API call and shows the running total in the UI. The counter and last-call timestamp are persisted across Node-RED restarts.
|
|
133
|
+
|
|
134
|
+
- Resets automatically when a rate-limit response is received (HTTP 403, error code `CU-429`)
|
|
135
|
+
- Can be reset manually via the **Reset counter** button or by sending `msg.resetCallCounter = true`
|
|
136
|
+
|
|
137
|
+
### Debug Mode
|
|
138
|
+
|
|
139
|
+
When **Debug Mode** is enabled, verbose `trace` and `info` messages appear in the Node-RED log, prefixed with `[bmw-cardata]`. Warnings and errors are always logged.
|
|
140
|
+
|
|
141
|
+
| Level | When logged |
|
|
142
|
+
|-------|-------------|
|
|
143
|
+
| `trace` | Debug mode only — token TTL, raw API responses, container lookup steps |
|
|
144
|
+
| `info` | Debug mode only — session loaded, token refreshed, container found/created |
|
|
145
|
+
| `warn` | Always — recoverable errors, 404 retries, rate limit hit |
|
|
146
|
+
| `error` | Always — failures that stop an operation |
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Nodes
|
|
151
|
+
|
|
152
|
+
### bmw-cardata-config
|
|
153
|
+
|
|
154
|
+
Central configuration node. Manages authentication, token refresh, and container lifecycle.
|
|
155
|
+
|
|
156
|
+
| Field | Description |
|
|
157
|
+
|-------|-------------|
|
|
158
|
+
| **Client ID** | API Client ID from the BMW CarData Portal |
|
|
159
|
+
| **VIN** | 17-character Vehicle Identification Number |
|
|
160
|
+
| **Debug Mode** | Enable verbose log output |
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
### bmw-cardata-soc
|
|
165
|
+
|
|
166
|
+
Reads the vehicle's **State of Charge (SoC)**. Always uses the three built-in default datapoints. For custom datapoints use `bmw-cardata-query` instead.
|
|
167
|
+
|
|
168
|
+
#### Input
|
|
169
|
+
|
|
170
|
+
| Property | Description |
|
|
171
|
+
|----------|-------------|
|
|
172
|
+
| any message | Triggers the request |
|
|
173
|
+
| `msg.vin` | Override the configured VIN |
|
|
174
|
+
| `msg.resetCallCounter = true` | Reset the API call counter before the request |
|
|
175
|
+
|
|
176
|
+
#### Output
|
|
177
|
+
|
|
178
|
+
| Property | Description |
|
|
179
|
+
|----------|-------------|
|
|
180
|
+
| `msg.payload` | SoC as integer, e.g. `75` *(SoC only mode)* |
|
|
181
|
+
| `msg.payload` | `{ soc, vin, timestamp, raw, apiCalls }` *(Full object mode)* |
|
|
182
|
+
| `msg.bmw` | Object with all fields above |
|
|
183
|
+
| `msg.apiCalls` | `{ count, lastCallAt }` |
|
|
184
|
+
| `msg.topic` | `bmw/{VIN}/soc` |
|
|
185
|
+
|
|
186
|
+
#### Settings
|
|
187
|
+
|
|
188
|
+
| Field | Description |
|
|
189
|
+
|-------|-------------|
|
|
190
|
+
| **Output mode** | `SoC only` (integer) or `Full object` |
|
|
191
|
+
| **Show call count** | Append API call count to node status text |
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
### bmw-cardata-query
|
|
196
|
+
|
|
197
|
+
Generic query node. Returns the full raw telemetry response for a configurable set of datapoints.
|
|
198
|
+
|
|
199
|
+
#### Container modes
|
|
200
|
+
|
|
201
|
+
| Configuration | Behaviour |
|
|
202
|
+
|--------------|-----------|
|
|
203
|
+
| Keys + Name | Finds or creates a container with those keys, named as specified |
|
|
204
|
+
| Keys only | Finds or creates a container with those keys, named `NR_Default` |
|
|
205
|
+
| Name only | Looks up an existing ACTIVE container by name, returns all its data |
|
|
206
|
+
| Neither | Uses the three built-in default keys |
|
|
207
|
+
|
|
208
|
+
An existing container whose keys are a **superset** of the requested keys will be reused — no new container is created unnecessarily.
|
|
209
|
+
|
|
210
|
+
#### Input
|
|
211
|
+
|
|
212
|
+
| Property | Description |
|
|
213
|
+
|----------|-------------|
|
|
214
|
+
| any message | Triggers the request |
|
|
215
|
+
| `msg.vin` | Override the configured VIN |
|
|
216
|
+
| `msg.resetCallCounter = true` | Reset the API call counter before the request |
|
|
217
|
+
|
|
218
|
+
#### Output
|
|
219
|
+
|
|
220
|
+
| Property | Description |
|
|
221
|
+
|----------|-------------|
|
|
222
|
+
| `msg.payload` | Full raw telematic data response object |
|
|
223
|
+
| `msg.apiCalls` | `{ count, lastCallAt }` |
|
|
224
|
+
| `msg.topic` | `bmw/{VIN}/query` |
|
|
225
|
+
|
|
226
|
+
#### Settings
|
|
227
|
+
|
|
228
|
+
| Field | Description |
|
|
229
|
+
|-------|-------------|
|
|
230
|
+
| **Container Name** | Name for new containers, or name to look up (name-only mode). Active container names are suggested as you type. |
|
|
231
|
+
| **Container Keys** | Datapoints to request, one per line. Leave empty for defaults or name-only mode. |
|
|
232
|
+
| **Show call count** | Append API call count to node status text |
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## Example Flow
|
|
237
|
+
|
|
238
|
+
A ready-to-import example flow is available at `examples/bmw-cardata-openwb-soc.json`.
|
|
239
|
+
|
|
240
|
+
It demonstrates a minimal setup: an Inject node fires every 30 minutes, the BMW SoC node fetches the current charge level, and an HTTP Request node forwards the value to an EV charging controller.
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Rate Limit
|
|
245
|
+
|
|
246
|
+
> ⚠️ The BMW CarData API allows a maximum of **50 calls per 24 hours**. The exact daily reset time is not documented by BMW.
|
|
247
|
+
|
|
248
|
+
Recommendations:
|
|
249
|
+
- Trigger SoC requests at an interval of **at least 30 minutes** (≤ 48 calls/day)
|
|
250
|
+
- Container list and detail requests also count against the limit — use the local cache
|
|
251
|
+
- Monitor the **API call counter** in the config node UI
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## API Endpoints
|
|
256
|
+
|
|
257
|
+
All endpoints are based on the official [BMW CarData Swagger spec](https://bmw-cardata.bmwgroup.com/customer/public/assets/swagger/swagger-customer-api-v1.json).
|
|
258
|
+
|
|
259
|
+
| Purpose | Endpoint |
|
|
260
|
+
|---------|----------|
|
|
261
|
+
| Device code | `POST https://customer.bmwgroup.com/gcdm/oauth/device/code` |
|
|
262
|
+
| Token | `POST https://customer.bmwgroup.com/gcdm/oauth/token` |
|
|
263
|
+
| Create container | `POST https://api-cardata.bmwgroup.com/customers/containers` |
|
|
264
|
+
| List containers | `GET https://api-cardata.bmwgroup.com/customers/containers` |
|
|
265
|
+
| Container details | `GET https://api-cardata.bmwgroup.com/customers/containers/{containerId}` |
|
|
266
|
+
| Delete container | `DELETE https://api-cardata.bmwgroup.com/customers/containers/{containerId}` |
|
|
267
|
+
| Telematic data | `GET https://api-cardata.bmwgroup.com/customers/vehicles/{vin}/telematicData?containerId=...` |
|
|
268
|
+
| Vehicle mappings | `GET https://api-cardata.bmwgroup.com/customers/vehicles/mappings` |
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## License
|
|
273
|
+
|
|
274
|
+
MIT
|