📄 docs: Add readme

This commit is contained in:
Keith Solomon
2026-06-06 10:31:18 -05:00
parent 122358286d
commit 801e16f7ff
+129
View File
@@ -0,0 +1,129 @@
# ESP32 "CYD" ThermoPro Bridge
A proof-of-concept bridge that reads temperature data from a **ThermoPro TP930** (among others) Bluetooth BBQ thermometer and ships it to a self-hosted HTTP API for storage and display.
## Architecture
```plain
ThermoPro TP930 (BLE)
thermopro_cli.py ←── BLE reader (reverse-engineered protocol, Linux only)
bridge_poc.py ←── polls CLI, normalizes payload, POSTs to API
receiver.php ←── stores latest reading + NDJSON log, serves status page
```
## Components
### `thermopro_cli.py`
Local copy of the [thermopro-cli](thermopro-cli/) tool. Communicates directly with the ThermoPro thermometer over BLE using a reverse-engineered protocol. Outputs probe temperatures, battery level, and unit as JSON.
### `bridge_poc.py`
Polling bridge that:
1. Calls `thermopro_cli.py` on a configurable interval
2. Normalizes the raw CLI output into a structured payload
3. POSTs the reading to the configured HTTP endpoint with a shared secret token
### `receiver.php`
Minimal PHP API server that:
- `POST /api/thermopro/readings` — accepts and validates a reading, writes it to `data/latest.json` and appends to `data/readings.ndjson`
- `GET /api/thermopro/latest` — returns the most recent reading as JSON
- `GET /` or `GET /status` — HTML status page (auto-refreshes every 10 seconds)
## Data Format
Each reading payload looks like:
```json
{
"deviceId": "tp930-smoker",
"device": "ThermoPro TP930",
"mac": "C9:48:1D:B1:E1:E7",
"connected": true,
"battery": 90,
"unit": "F",
"probeCount": 4,
"probes": [
{ "id": 1, "name": "Probe 1", "temperature": 266.2, "connected": true },
{ "id": 2, "name": "Probe 2", "temperature": null, "connected": false },
{ "id": 3, "name": "Probe 3", "temperature": null, "connected": false },
{ "id": 4, "name": "Probe 4", "temperature": null, "connected": false }
],
"readingTime": "2026-06-06T12:00:00+00:00",
"bridgeTime": "2026-06-06T12:00:01+00:00",
"source": "thermopro_cli"
}
```
## Requirements
- **Bridge host:** Linux with Bluetooth (BlueZ), Python 3.8+, `bleak` library
- **API server:** PHP 8.x with write access to the `data/` directory
## Setup
### 1. Install Python dependencies
```bash
pip install bleak
```
### 2. Configure the receiver
Deploy `receiver.php` to a PHP-capable web server. Set the `THERMOPRO_BRIDGE_TOKEN` environment variable (or it defaults to `dev-secret`):
```bash
export THERMOPRO_BRIDGE_TOKEN="your-secret-token"
```
### 3. Run the bridge
```bash
python bridge_poc.py \
--cli thermopro_cli.py \
--endpoint https://your-server/api/thermopro/readings \
--token your-secret-token \
--device-id tp930-smoker \
--mac C9:48:1D:B1:E1:E7 \
--interval 15
```
**Options:**
| Flag | Default | Description |
| --- | --- | --- |
| `--cli` | `thermopro_cli.py` | Path to `thermopro_cli.py` |
| `--endpoint` | `http://127.0.0.1:8000/api/thermopro/readings` | API endpoint |
| `--token` | `dev-secret` | Shared token (`X-Bridge-Token` header) |
| `--device-id` | `tp930-smoker` | Stable identifier for this device |
| `--mac` | `C9:48:1D:B1:E1:E7` | ThermoPro BLE MAC address |
| `--interval` | `15` | Polling interval in seconds |
| `--once` | — | Read and POST once, then exit |
### Finding your device's MAC address
```bash
python thermopro_cli.py scan
```
## Data Storage
| File | Contents |
| --- | --- |
| `data/latest.json` | Most recent reading (overwritten each poll) |
| `data/readings.ndjson` | Append-only log of all readings (newline-delimited JSON) |
## Security
- The API endpoint is protected by a shared secret sent as the `X-Bridge-Token` request header.
- Use HTTPS for the endpoint in production to keep the token confidential.
- The token is compared with `hash_equals()` to prevent timing attacks.