Work more on Bluetti
This commit is contained in:
@@ -35,7 +35,7 @@ three; which one you use depends on your model's generation.
|
||||
| # | Channel | Where | Status | Use for |
|
||||
|---|---|---|---|---|
|
||||
| 1 | **`BluettiBLE`** — BLE GATT connection | `src/BluettiBLE.*` | ✅ **Working** (builds, on-hardware-pending per model) | Older/plaintext models — full read **+ control** |
|
||||
| 2 | **`BluettiADV`** — BLE advertisement broadcast | `src/BluettiADV.*` | ⏳ **Ready, blocked on key** | Newer encrypted models — read-only, local |
|
||||
| 2 | **`BluettiADV`** — BLE advertisement broadcast | `src/BluettiADV.*` | 🔑 **Key obtained, on-hardware validation pending** | Newer encrypted models — read-only, local |
|
||||
| 3 | **Cloud Open API** — HTTPS | `cloud/bluetti.mjs` | ⏳ **Ready, pending account approval** | Any model incl. EL300 — read **+ control**, via cloud |
|
||||
|
||||
### 1. `BluettiBLE` — local GATT connection ✅ Working
|
||||
@@ -45,13 +45,15 @@ plaintext generation** (AC300, AC200M, EB3A, EP500P, …). The library compiles
|
||||
links; per-model field maps are ported from the reference project and want a
|
||||
final on-hardware sanity check. See [Quick start](#quick-start).
|
||||
|
||||
### 2. `BluettiADV` — local advertisement broadcast ⏳ Ready, blocked on key
|
||||
### 2. `BluettiADV` — local advertisement broadcast 🔑 Key obtained
|
||||
Passively decodes the encrypted monitoring broadcast that **newer** units emit
|
||||
(Elite / V2 / EP600 / AC180 / AC200L …). Read-only, no connection. The decoder is
|
||||
implemented (AES-128-CTR + the official BLE-ADV field layout) and builds, but it
|
||||
needs the device's **16-byte AES key**, which Bluetti has not yet exposed in the
|
||||
app for these models. Ready to run the moment a key is available. See
|
||||
[Advertisement mode](#advertisement-mode-bluettiadv).
|
||||
implemented (AES-128-CTR + the official BLE-ADV field layout) and builds. The
|
||||
device's **16-byte AES key** is now available (exported from the app — see
|
||||
[Advertisement mode](#advertisement-mode-bluettiadv)); the AdvMonitor example is
|
||||
wired with it and matches the first broadcaster automatically. Remaining step is an
|
||||
on-hardware capture to confirm the key/nonce/offsets — validate offline with
|
||||
`tools/decode.mjs` against a captured packet.
|
||||
|
||||
### 3. Cloud Open API — HTTPS ⏳ Ready, pending account approval
|
||||
For encrypted models (incl. the **EL300**) whose local channels are locked, the
|
||||
@@ -228,12 +230,38 @@ connection but **broadcast** an encrypted monitoring snapshot in their BLE
|
||||
advertisements — no connection, no pairing, multiple listeners, low power. This is
|
||||
the same scheme Victron uses. `BluettiADV` reads it.
|
||||
|
||||
You need two things from the owner's side:
|
||||
You need the **16-byte AES key** (32 hex chars) — from the BLUETTI app or the
|
||||
device's Webserver (Bluetooth-data / developer section). The export is a small CSV
|
||||
whose **3rd line is the AES key**; e.g.:
|
||||
|
||||
1. The **16-byte AES key** (32 hex chars) — copy it from the BLUETTI app or the
|
||||
device's Webserver (Bluetooth-data / developer section).
|
||||
2. The device's **BLE MAC address** — a scanner app shows it; confirm the unit
|
||||
broadcasts manufacturer data starting `06 0F` (company ID `0x0F06`).
|
||||
```
|
||||
bluetti
|
||||
1780650490894 # timestamp / PIN (unused)
|
||||
53afcd9aef4ff020f472686c00283ce5 # <-- the 16-byte AES key
|
||||
6bc305f0… # token (unused for advertisements)
|
||||
```
|
||||
|
||||
The **BLE MAC is optional**: pass `""` and the first Bluetti broadcaster the ESP32
|
||||
hears is adopted automatically (set a real MAC only if several Bluetti units are
|
||||
in range). Confirm the unit broadcasts manufacturer data starting `06 0F` (company
|
||||
ID `0x0F06`) with a scanner, or just run the example with debug on.
|
||||
|
||||
> **Validate the key offline first (no hardware):** capture a `raw:060f…` line
|
||||
> from the AdvMonitor debug output and run
|
||||
> `node tools/decode.mjs '<paste it>'`. It reads the key from the CSV, AES-CTR
|
||||
> decrypts the packet, and prints the decoded fields with sanity checks — so you
|
||||
> know the key works before relying on it.
|
||||
|
||||
> **First check the unit actually broadcasts telemetry.** Run AdvMonitor with
|
||||
> debug on and look at your Bluetti's line:
|
||||
> - `… mfg:060f… <- BLUETTI TELEMETRY (0x0F06)` → telemetry is being broadcast;
|
||||
> `BluettiADV` decodes it.
|
||||
> - `… mfg:424c… <- Bluetti nameplate only, NO telemetry` → the unit advertises a
|
||||
> static "BLUETT" nameplate (company id `0x4C42`) but **no monitoring payload**.
|
||||
> Observed on EL300 / EL100 V2: the BLE-ADV broadcast feature isn't enabled on
|
||||
> that firmware. Look for a "Bluetooth broadcast / open data" toggle in the app;
|
||||
> if there's none, use the **Cloud Open API** instead. (On these units the
|
||||
> exported AES key is the GATT secure-channel key, not an advertisement key.)
|
||||
|
||||
```cpp
|
||||
#include <Arduino.h>
|
||||
@@ -254,8 +282,8 @@ void setup() {
|
||||
bluetti.begin(5);
|
||||
bluetti.setDebug(true);
|
||||
bluetti.setCallback(onAdv);
|
||||
bluetti.addDevice("My Elite", "AA:BB:CC:DD:EE:FF",
|
||||
"112233445566778899aabbccddeeff00");
|
||||
bluetti.addDevice("My Elite", "" /* empty MAC = match first broadcaster */,
|
||||
"53afcd9aef4ff020f472686c00283ce5");
|
||||
}
|
||||
|
||||
void loop() { bluetti.loop(); }
|
||||
|
||||
Reference in New Issue
Block a user