Files
steveandClaude Opus 5 ba0c3b58b6 Initial commit: PT1000 probe emulation bridge
Feeds third-party BBQ probes into a pellet grill's wired probe jacks by
presenting the resistance a real PT1000 RTD would show at that temperature.
The grill sees an ordinary wired probe, so its display, app, target-temp
alarms and Keep Warm all work with no protocol reversing involved.

Pluggable probe sources: ThermoWorks RFX (via ThermoWorks Cloud), MEATER
(community-derived BLE decode), a synthetic simulator for hardware-free
development, and a Combustion stub.

Two safety invariants are load-bearing:
- Stale, missing or implausible readings drive the channel cold, never hot.
  A stuck-hot channel could convince the grill a cook finished early.
- Unimplemented sources raise rather than returning plausible numbers, since
  the grill acts on these values.

Cloud sources are dated by the cloud's own timestamp rather than by fetch
time, because ThermoWorks serves a dead probe's last value with a fresh 200.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-16 22:46:14 -04:00

4.1 KiB

smokescreen

Feed third-party BBQ probes (MEATER, ThermoWorks, Combustion) into a pellet grill's wired probe jacks, so they show up as native probes on the grill display and in the vendor app — with working target-temp alarms and Keep Warm.

Developed and tested against a Traeger Ironwood (2022 touchscreen WiFire), but the technique is just PT1000 emulation, so it should carry to any grill using the same 3.5 mm PT1000 jacks — Pit Boss, Camp Chef, GMG and friends.

The name is the mechanism: the grill is looking at a probe that isn't there.

How it works

your probes ──BLE──> Raspberry Pi ──I²C──> AD5272 rheostat ──3.5mm──> Traeger jacks 1 & 2

The Ironwood's wired jacks take PT1000 RTDs — 1000 Ω at 0 °C, ~3.85 Ω/°C, a published standard curve. So instead of breaking Traeger's wireless pairing, we just be a PT1000: read your probe over BLE, compute the resistance a real PT1000 would have at that temperature, and present it to the jack.

No protocol to reverse, nothing to re-break after a firmware update, and the grill's own logic works because as far as it knows, nothing unusual happened.

Why not MITM the wireless probes — and why one nRF52840 dongle can't anyway — is in docs/PROTOCOL_NOTES.md.

Start here

Before writing code or buying parts, do Step 0 in docs/HARDWARE.md: put a plain 1.2 kΩ resistor in a 3.5 mm plug, plug it into jack 1, and check the grill reads ~127 °F. That one experiment validates this entire design in ten minutes with a multimeter and a junk-drawer resistor.

Quick start

python3 -m venv .venv && .venv/bin/pip install -e '.[dev]'

Run the whole pipeline with no hardware at all — simulated probes, no I²C writes:

cp config.example.yaml config.yaml && .venv/bin/smokescreen run --dry-run
jack1=20.3C/1079ohm [Simulated probe 1]  jack2=17.2C/1067ohm [Simulated probe 2]

The PT1000 reference table, for bench work with a multimeter:

.venv/bin/smokescreen table

On the Pi, with hardware wired and calibrated:

.venv/bin/smokescreen run

Adding a probe vendor

Subclass ProbeSource, emit ProbeReading objects, register it in sources/__init__.py. Nothing else changes — the router and the PT1000 emulator never learn what hardware produced a number.

Source Status
simulator Works. Synthetic cook curve with a stall, for development
thermoworks RFX via ThermoWorks Cloud. Needs pip install '.[thermoworks]'
meater Implemented from community reverse engineering — verify on the bench
combustion Stub. Open published spec, easiest to finish

With more probes than jacks — four RFX probes into two jacks — list what's visible and pin the two you want:

.venv/bin/smokescreen discover

Unimplemented sources raise rather than returning plausible-looking numbers. The grill acts on these values, so a driver that silently invents data would be worse than one that refuses to start.

Safety

Stale, missing, or implausible readings drive the channel cold, never hot. A stuck-hot channel could convince the grill a cook finished early; a stuck-cold one can only look obviously wrong. Details and the reasoning are in docs/HARDWARE.md.

This is a hobby project driving a fire with reverse-engineered numbers. Keep a real probe in the cook until you have several successful runs behind you.

Layout

src/smokescreen/
  pt1000.py              IEC 60751 curve math — the part that must be right
  models.py              ProbeReading, ChannelState
  router.py              which probe drives which jack
  bridge.py              orchestration loop
  sources/               probe backends (add vendors here)
  outputs/               rheostat driver + PT1000 emulator
docs/HARDWARE.md         wiring, BOM, calibration, Step 0
docs/PROTOCOL_NOTES.md   what we know per vendor, and how much to trust it