888 Commits

Author SHA1 Message Date
ProfBoc75
f47b0b7a71 Add Bresser SmartHome Garden decoder for soil moisture and water timer
Initial FSK PCM decoder for the Bresser SmartHome Garden 433 MHz irrigation
set (Fujian Baldr / Homgar / RainPoint family): soil moisture sensor and
water timer.
2026-07-22 22:49:45 +02:00
Benjamin Larsson
0206016a88 Add Silver Spring Networks mesh decoder
Closes #3583.
2026-07-20 19:49:53 +02:00
Benjamin Larsson
de1ee35e8e Add support for Cotech 36-7900 rain gauge
Reverse-engineered in issue #3537: OOK PPM, 60 bit frame, no computed
checksum found. Byte layout confirmed against a full day's real
capture data -- temperature (12 bit signed, scale 10) tracks a smooth
diurnal curve from 14.7 to 23.6 C, and the rain field is a monotonic
counter that jumped by ~39-42 per confirmed bucket tip in a controlled
test and stayed flat otherwise. The mm-per-count scale wasn't
established (no water-volume calibration reported), so the rain count
is exposed raw rather than guessed at.

Bit-level analysis across all 66 unique real codes seen showed a 24
bit span that's exactly zero in every one -- likely reserved bits
rather than a coincidence, but functionally just as good as a checksum
for rejecting noise, so it's checked as one. This also narrowed the
rain field from an assumed 36 bits down to the 12 that actually vary.

Disabled by default since the reserved-bits check is a plausibility
gate, not a real computed checksum.

Closes #3537.
2026-07-19 22:25:21 +02:00
Benjamin Larsson
b9d5b6a13a Add support for Honda (TRW PPA-GF33) TPMS
FSK, IEEE 802.3 Manchester coded, distinguished from Chrysler-fitment
TRW sensors (tpms_trw.c) by a different desync marker and byte layout.
Reverse-engineered in issue #3447: byte layout confirmed via CRC-8/SMBUS
validation across all captures, sensor ID confirmed against both the
value printed on the physical sensor and a commercial TPMS tool reading,
and the pressure/temperature formulas fit a 7-point pressure sweep from
the same tool (one very-low-pressure point didn't fit, noted as an
open question in the doc comment rather than guessed at).

Closes #3447.
2026-07-19 21:00:54 +02:00
Benjamin Larsson
b38e7e130c Add Jeep TPMS decoder for the doubled-pressure Continental variant
2021 Jeep Grand Cherokee (WK2) sensors, reported as Continental by an
OBD-II scanner, transmit the exact same wire format as Citroen TPMS
(protocol 82) but with pressure at twice Citroen's raw * 1.364 scale.
Confirmed against a session where all 4 tires were set to 33-36 PSI:
the doubled formula lands in that range, the existing one reports
exactly half.

Registered as a new, disabled-by-default protocol (380) rather than
changing Citroen's formula, since the two are not reliably
distinguishable on the wire and changing Citroen would break existing
users. Both decoders fire on the same data; select the one that
matches your vehicle with -R.

Closes #3364.
2026-07-19 18:09:57 +02:00
Christian W. Zuckschwerdt
263ac3e867 Fix automatic discriminator selection for file input (#3554) 2026-07-19 13:23:37 +02:00
Benjamin Larsson
dd7ac204af Add RADIAN/RADIAN0 meter transport decoder (issue #3408)
FSK_PCM at 2400 baud, UART 8N2 framing, CRC-16/KERMIT trailer. Outputs
the verified transport fields (length, control, sender/receiver ID,
CRC) and raw body bytes only; the response body looks M-Bus-like but
isn't decoded yet.

Lives in m_bus.c rather than its own file: the body is a wired M-Bus
telegram (see next commit), so this reuses the wM-Bus DIF/VIF decoder
already there instead of duplicating it. Registered as protocol 379.
2026-07-19 02:15:24 +02:00
Benjamin Larsson
5a4d4880d3 Add Sefis M3 / Careud / Sykik SRTP300 TPMS decoder (closes #3342)
FSK_PCM Manchester-coded, CRC-16/XMODEM verified against 24 real
frames from the issue thread (a controlled 2.6->0.1 bar deflation
series). Ported and re-verified from a community draft
(tpms_sefis_m3_draft.c): independently confirmed the CRC, the
pressure "page" field layout, and the temperature formula against
the same 24 real frames via on-air Manchester-encoded test vectors
built from scratch (not just re-running the draft's own claims).

Fixed a units bug in the ported pressure formula (divisor 1024 gives
tenths of a bar, not bar -- corrected to 10240).

Pressure: 20/24 exact to 0.1 bar, 24/24 within +-0.1 bar (all misses
biased -0.1, suggesting the 0x0e00 offset constant is slightly off
rather than the field being wrong). Temperature: 23/24 exact.
B3/B6 and a fixed sensor ID remain unsolved.
2026-07-19 01:27:34 +02:00
Christian W. Zuckschwerdt
2d029fbf36 Refactor to add proper package flush (#3619) 2026-07-18 23:55:03 +02:00
Benjamin Larsson
4e127c7d30 Add Typhur Sync Gold meat thermometer probe decoder (closes #3138)
FSK_PCM at 12.5 us/bit, CRC-16 (poly 0x8005, init 0x0000). Ported and
independently re-verified from an unmerged fork (hakong/rtl_433,
feat-typhur branch) referenced in the issue: re-derived the sync word
and payload location via raw bit search (not trusting the fork's own
CRC self-check), confirmed CRC valid on all 19 real captures across
two physical probes, and confirmed the decoded values are physically
sane -- T1-T5 and ambient temperatures match the reporter's own noted
ranges, battery voltage is stable per probe, and the counter
increments monotonically per probe ID.
2026-07-18 19:44:02 +02:00
Benjamin Larsson
d4df8fcc73 Revert "Extend FSK modulation to the full set of OOK pulse-slicer codings (closes #3409)"
This reverts commit 3d75051e1d.
2026-07-18 18:21:52 +02:00
Benjamin Larsson
03fad62ee7 Add McPower Kinetic battery-less wall switch decoder (closes #3102)
FSK_PCM at 100 kbps, CRC-16 (poly 0x1021, init 0xaa55) verified against
9 hex codes posted in the issue thread. No raw IQ capture was ever
attached to the issue, only demodulated hex -- enabled by default since
the 16 bit CRC gives strong protection against false positives.
2026-07-18 18:05:14 +02:00
Benjamin Larsson
f4c33bbc5b Add LaCrosse WS6868 weather station decoder (closes #3120)
FSK_PCM at 58 us/bit, verified against 22 real captures across both
sensors (TX232TH-LCD temperature/humidity: 10/10 exact match against
the sensor's own displayed readings; TX231RW wind/rain: header/CRC/
checksum confirmed but the wind/rain payload itself is unconfirmed --
every available capture has it fixed at the same value with no wind
or rain occurring, so it's reported as data_raw rather than guessed at).
Enabled by default: both frame types are protected by CRC-8, TX231RW
additionally by a whole-frame checksum.
2026-07-18 18:05:14 +02:00
Benjamin Larsson
3d75051e1d Extend FSK modulation to the full set of OOK pulse-slicer codings (closes #3409)
pulse_slicer_ppm/dmc/piwm_raw/piwm_dc/osv1/nrzs/rzi only operate on the
abstract pulse/gap width sequence already common to both the OOK and
FSK demod paths (proved by the 3 codings -- PCM, PWM, Manchester
zerobit -- that already reuse the same functions for FSK). Adds the
remaining 7 as FSK_PULSE_* enum values, wires them into
run_fsk_demods(), and exposes the ones already flex-parseable for OOK
(PPM, DMC, PIWM_RAW, PIWM_DC, MC_OSV1) as FSK_* flex modulation strings.
NRZS/RZI aren't exposed via flex for OOK either, so left the same way
for FSK for now -- purely additive, no existing modulation changed.
2026-07-18 12:15:34 +02:00
Benjamin Larsson
7f97a22be3 Add Elster type-2 frame decoder (closes #3618)
Type-2 is a distinct physical layer from the existing Manchester type-1
decoder: FSK_PCM (not Manchester), 0xaa whitening (not 0x55), 16 bit
length, ~4x the bit rate -- confirmed at 7 us/bit against a reporter-
supplied manifest of 32 real captures with independently-computed frame
hex. Decodes the msg 0x56/0x57 class byte, addressing, and neighbour-
table entries; encrypted (AES-ECB, per-meter key) and other cleartext
payloads are reported as data_raw. Ships disabled, same as type-1.
2026-07-18 03:26:28 +02:00
Benjamin Larsson
850639575e Add Elero bidirectional blinds/awning remote decoder
Reverse engineered in issue #3083 (Silent Gliss SG11490 wall switch,
Elero's general 868/915 MHz protocol): CC1101-style GFSK/PCM framing,
IBM whitening, CRC-16, and a fixed reversible command obfuscation
(verified against 38 CRC-valid real captures across 4 channels).
2026-07-18 02:58:58 +02:00
Benjamin Larsson
8ab9b81405 Add disabled decoder for Hanwell ML/RL4000-series Radiologger
FSK PWM, byte-reversed 40-bit frame, 8-bit additive checksum. Verified
against 4 real captures in issue #2942: all match the reference table
exactly (id, temperature_raw, humidity_raw). Reports raw 12-bit counts
only -- engineering-unit calibration is transmitter-specific and lives
in the Hanwell base station, not the radio protocol. The real 40-bit
frame is always the last demodulated row (earlier rows are leftover
preamble noise). Ships disabled: the one working capture needs
non-default -Y demod-assist flags to lock on at all.
2026-07-17 23:49:53 +02:00
Benjamin Larsson
7c04fa91fc Add disabled decoder for 2GIG-KEY2E-345 encrypted keyfob
Same preamble/Manchester family as honeywell.c but a longer 72-bit
frame, single preamble search (no repeats observed in this signal).
CRC-16 (poly 0x8005, init 0x4c57) verified against 7 real codes from
issue #2584. The 32+16 bit payload is encrypted and undecoded, so
id/status are reported as opaque hex, and the decoder ships disabled.
2026-07-17 21:45:08 +02:00
Benjamin Larsson
67c83471a8 Add disabled decoder for Cotech FT0203/18-3676 anemometer
Reverse-engineered in issue #2569 (CRC-8 poly 0x31 init 0xc0, 72-bit
frame) but never previously shipped as a working decoder. Brute-force
searches the row for the CRC-valid frame, sidestepping the manchester
zerobit alignment ambiguity noted in the thread. No real IQ capture
exists, so it ships disabled pending field verification.
2026-07-17 19:28:40 +02:00
Benjamin Larsson
0dc4c975aa Add support for Cavius door/window sensor
Different, simpler protocol than the existing smoke/heat/water Cavius
decoder (issue #2562): raw FSK_PCM at 415 us/bit, CRC-8 verified.
Registered as protocol 368.

Byte layout and CRC found by ProfBoc75 via manual PulseView bit
transcription, since captures in the issue were too weak for automatic
detection. Verified against 2 real captures (need -Y level=-14) and 2
more transcribed frames; all 4 pass CRC and match reported state.
2026-07-17 17:48:17 +02:00
Benjamin Larsson
f0c2b6fe12 Add support for TFA 30.3307.02 wind sensor
CC110L-unrelated OOK Return-to-Zero inverted (RZI) coding (see
pulse_slicer_rzi()), part of TFA's "WeatherHub" product line. See
https://github.com/merbanan/rtl_433/issues/2453.

The raw RZI-decoded bitstream is then de-PSK, de-NRZS, and G3RUH
descrambled -- the same receiver-agnostic bit-recovery approach used by
the independent "tfrec" project (https://github.com/baycom/tfrec, in
whb.cpp) for TFA WeatherHub sensors. Its documented WeatherHub protocol
(also confirmed here, independently, against 3 real captures) is
layered on top: a 32-bit frame sync word, a device ID (doubling as a
sensor type byte), a CRC-32 over the payload, and this wind sensor's
own payload format (direction/speed/gust/reading-age).

Verified against 3 independent real captures: CRC-32 validates on all
3, all report the same device ID, and reported wind speed/gust are
consistently 0.0 m/s with a static direction -- physically plausible
for a stationary/manual test transmission (matching the reporter's own
description of pressing the sensor's button indoors, wind vane not
exposed to real wind).
2026-07-17 16:47:43 +02:00
Benjamin Larsson
ca3ddb571d Add OOK_PULSE_RZI pulse-slicer for RZ unary run-length coding
A new core modulation type/slicer for a coding where the signal is high
almost all the time, with brief low dips marking 0-bits, and the high
duration between dips is a whole multiple of a fixed period counting
that many consecutive 1-bits.

Named RZI: Return-to-Zero inverted. This coding is the opposite of the
project's usual OOK convention (low energy/long = 0, high energy/short
= 1): here the short dip is the 0-bit and a long high run is one or
more 1-bits.

No decoder uses this yet.
2026-07-17 16:47:43 +02:00
Benjamin Larsson
5a35e6efc7 Add support for Watts Vision thermostat
CC110L-based FSK protocol, 26 us symbols, GFSK/FSK_PULSE_PCM. Both the
application-layer CRC-16/MODBUS and the CC110L's own hardware
CRC-16/CMS are validated as independent accept/reject gates before any
field is decoded.

The application payload is a generic tag+length record stream (value
length is encoded in each tag byte's own top two bits), not a layout
fixed per message type, which lets the same walker decode both the
base -> endpoint command/state messages and the endpoint -> base
status reports:

- temperature_F: primary measured temperature (tag 0x4b).
- temperature_2_F: secondary floor/external temperature (tag 0x5e).
- mode_setpoint_F / setpoint_mode: active setpoint and its operating
  mode bank (tag 0x8a: Comfort/Off/Anti-freeze/Reduced-ECO/Boost-Timer/
  Auto phases/Manual-Temporary).
- setpoint_min_C / setpoint_max_C / sensor_mode / sensor_flags_raw:
  installer-configured setpoint range and regulation-sensor selection
  (tag 0x8e: Amb/FLR/FLL/Air).
- floor_limit_1_F / floor_limit_2_F: floor-limit temperature pair, only
  meaningful in FLL sensor mode (tag 0xcc).
- diagnostic_code / diagnostic_flags: per-zone diagnostic state
  (tag 0x4c).
- report_flags_0/1/2: packed report/update state (tag 0x8d), including
  a known update-gate bit for the paired 0x8a value.
- association_id / state_raw / flags_raw: per-endpoint association id
  and state bytes (tags 0x03/0xdf/0x3b) from command/state messages.

A raw value of 0x084c marks a temperature field as sensor-unavailable
and is omitted rather than reported as a bogus ~212.4 F reading; a zero
floor-limit word is likewise omitted rather than reported as 0.0 F.

Fields not yet covered by the above are logged and skipped rather than
guessed at, since the record stream is walked generically instead of
assuming a fixed frame.
2026-07-17 12:54:34 +02:00
Benjamin Larsson
bdf6e4721d Convert wind_*_m_s fields under -C customary (#2846)
-C si/-C customary had no handling at all for _m_s-suffixed fields
(wind_avg_m_s, wind_max_m_s, used by the Fineoffset WS80/WS90/WS85
decoders), so customary users of those sensors never got a mi/h
conversion. Add mps2mph() alongside the existing kmph2mph/mph2kmph
helpers, and wire up the _m_s -> _mi_h conversion in both the value
conversion path and the CSV field-header conversion. -C si is
unaffected since m/s is already the SI unit.

The broader ask in the issue (a switch to force all wind speed fields
to one common unit) is not addressed here - the maintainer thread
never reached consensus on which unit combination makes sense.
2026-07-17 01:25:32 +02:00
Bruno OCTAU
f8fa455c8e Add support for Mercedes Benz Sprinter TPMS sensor (#3553)
* Add support for Mercedes Benz Sprinter TPMS sensor

* fix: stabilize Sprinter TPMS decoding (#3595)

Co-authored-by: RomeoApps <294788459+RomeoApps@users.noreply.github.com>

---------

Co-authored-by: RomeoApps <romeo@romeoapps.com>
Co-authored-by: RomeoApps <294788459+RomeoApps@users.noreply.github.com>
2026-07-17 00:01:47 +02:00
Benjamin Larsson
2110cdbe76 Add Elsner Solexa 230V decoder
FSK Manchester zerobit, on-air CRC-16 (poly 0x1021, init 0x68b3) as the
integrity gate. Removes a self-synchronizing transform (x^7 + x^5 + 1)
to recover a constant sync marker, and parses the raw on-air payload's
rolling state, transmission counter, and command (open/close/stop/
automode) from a relocated, state-normalized byte pair. See the
decoder's doc comment for the full derivation and known limits.

Enabled by default; CRC-16 gates false positives.
2026-07-16 21:58:35 +02:00
Christian W. Zuckschwerdt
1460e37947 minor: Fix union field order 2026-07-16 18:21:23 +02:00
Christian W. Zuckschwerdt
d17901b796 Add output file reopen on sighup (#3282) 2026-07-16 17:55:25 +02:00
Benjamin Larsson
4d37e6f9da Add support for Oregon Scientific WMR500 weather station
Closes #2407. FSK PCM, ~26 us bit width, inverted levels. Reverse
engineered from 3 years of prior investigation in the issue (confirmed
preamble, message framing, and CRC-16, though the actual sensor payload
was never solved) plus new work correlating the reporter's own log
against the one piece of ground truth available: display readings
drifting from 7.1 C/59% humidity to 9.9 C/49% humidity over a real
session.

Humidity is confirmed exactly against both ends of that session (not
approximately -- exact integer matches). Temperature is fit from the
same 2 reference points, which is the bare minimum for a 2 parameter
linear model with no slack to validate against a third point, so it's
documented as a rough estimate pending wider-range calibration data.

Only the "long" message kind (of two seen on air, sharing a 14 byte
header) is decoded; the "short" kind's extra payload (suspected wind
data) is not decoded.
2026-07-15 23:22:30 +02:00
Benjamin Larsson
12de24bb00 Add support for Jansite TPMS TY588-EU2
Closes #2320. A different, Manchester-coded FSK protocol from the older
Jansite Solar TPMS in tpms_jansite_solar.c (different preamble, no CRC) --
confirmed a genuinely different wire format, not a decode bug in the
existing decoder.

Verified against 15 real messages spanning a slow 1.6-2.8 bar pressure
ramp on one real sensor: temperature matches exactly on all 15; pressure
matches within one 2.5 kPa sensor step on all 15 (display rounding, not a
decode error). No real CRC exists; a tail-byte-repeat check is used as
the integrity check instead.

Sensor ID and battery status are not decoded: doing so needs samples from
a second physical sensor, which has never been posted to the issue.
2026-07-15 20:30:31 +02:00
Benjamin Larsson
f826667407 Add support for Kidde RF-SM-DC wireless-interconnect smoke alarm
Closes #2240. OOK, differential Manchester coded, 400 us chip width,
preceded by a non-DMC de-sync preamble (decode retries past it). Reverse
engineered and verified against real captures from two independent
reporters (5 real .cu8 files across 4 DIP-switch settings, all posted to
the issue), including one whose repeats span a full multi-second capture.

The DIP-switch double-send check is not a real CRC; a repeated-row
requirement was tried but does not work for this device, since real
repeats arrive 60-125 ms apart, past rtl_433's own global ~10 ms
same-reception cutoff, so no two repeats are ever seen in one bitbuffer.
Disabled by default to reflect the resulting weak validation.

Only the periodic idle/presence "heartbeat" message is confirmed; no
alarm/test/low-battery capture has ever been posted to the issue, so
those states are not decoded.
2026-07-15 17:29:02 +02:00
Christian W. Zuckschwerdt
45e9ac1a00 Add support for Baldr HCS528ARF pool thermometer (#3605)
Co-authored-by: Bruno OCTAU <62882637+ProfBoc75@users.noreply.github.com>
2026-07-14 18:35:09 +02:00
Benjamin Larsson
928817e0ef Add support for Kingspan/Watchman Plus (Niveau) oil tank monitor
Protocol reverse engineered from real captures and analysis in
https://github.com/merbanan/rtl_433/issues/2133 and the earlier
https://groups.google.com/g/rtl_433/c/VJSPl7h0848 thread, re-derived from
scratch and cross-checked against 18 real messages from 3 independent
devices (ID, level, and battery-low all confirmed; no whole-message
checksum found). RF timing (short_width/long_width) is a best estimate
from real captures in both threads, not live-verified end-to-end -- see
file header.
2026-07-14 12:20:43 +02:00
Benjamin Larsson
dd55d46960 Add support for Eberle Instat 868r1 floor heating thermostat remote
Protocol reverse engineered from real captures and analysis linked in
https://github.com/merbanan/rtl_433/issues/1951 (dottoreD/rtl_433_tests)
and cross-checked against 963 real examples (927 Learn + 36 On/Off), plus
independently confirmed action codes from crasu/gnu-heating. Modulation
timing is a best estimate (see file header) pending live hardware or a
raw capture that decodes end-to-end.
2026-07-14 01:46:07 +02:00
Benjamin Larsson
e48537c525 Add decoder for Auriol HG04641A temperature station
https://github.com/merbanan/rtl_433/issues/2014: the protocol was fully
reverse-engineered in the issue (OOK PPM timing, checksum, 2's-complement
temperature confirmed via a freezer test, battery-low bit confirmed via
an old-vs-fresh-battery comparison, even a working Arduino sketch) but
never ported into rtl_433 before the reporter lost interest.

Verified against all of the issue's distinct examples via -y, including
a low-battery reading and a second physical unit from a neighbor's
device. One correction: the original post's "-22.6 C" label for one
capture doesn't match the checksum-verified 2's-complement decode (which
gives +22.6 C) -- that label predates the freezer test that established
the actual encoding, so it looks like an early mislabeling rather than a
real discrepancy.

The wire checksum is only 4 bits, too weak to reject noise reliably on
its own -- enabling this against the full rtl_433_tests corpus produced
two dozen false positives on unrelated weather-sensor protocols with
similar OOK/PPM timing. Added a flags-nibble check and a plausible
temperature range, both satisfied by every real capture available, which
eliminates all of them.
2026-07-13 23:12:15 +02:00
Christian W. Zuckschwerdt
0b1c699013 minor: Clean up microseconds in comments 2026-07-13 22:47:01 +02:00
Christian W. Zuckschwerdt
e8242d61dd Refactor Fineoffset WH2 BREAKING change for Agimex Rosenborg 66796 (#3603)
Enable protocol 356 if you have a Rosenborg-66796.
2026-07-13 22:22:18 +02:00
Benjamin Larsson
596f47a54d Add decoder for Jansite TPMS TY-468-eu2 / KKMOON TPMS
https://github.com/merbanan/rtl_433/issues/2025: same SP372-chip-family
OOK/Manchester encoding as tpms_imars_t240.c (#1820, confirmed the same
by @zuckschwerdt in comment #34). Unlike #1820, this issue has real
device-display PSI/C readings paired with raw codes, which is what lets
this one be an actual verified decoder instead of a guess.

B3/B4 are still an affine function of B0, and temperature/pressure follow
the same byte-sum shape guessed for #1820: temperature_C = temp_offset -
(B2+B5)%256, pressure_kPa = (pressure_offset - (B5+B6)%256) * 2.5. Two
physical units are confirmed, each with its own checksum and offsets
(0xfb: 224/273, 0x64: 153/201), both fit against real ground truth in
the issue: 9/10 and 3/3 distinct temperatures match exactly, pressure
matches within ~0.5 PSI (manual gauge reading precision).
2026-07-13 21:55:58 +02:00
Benjamin Larsson
9851e7bdcb Add decoder for iMars T240 TPMS
https://github.com/merbanan/rtl_433/issues/1820: OOK, Manchester encoded,
50 us half-bit signal mistaken for XOR/stream-cipher encryption for years,
since only a tail-byte and a low-nibble check were ever confirmed.

B3 and B4 are each an affine function of B0 (B3 = B0 - k1, B4 = k2 - B0),
making (B3 + B4) mod 256 a fixed per-unit checksum. Two physical sensor
units are confirmed in the issue's captures, with checksums 0x41 and
0x3c; both are recognized here.

Verified against all 9 real packets in samples2.zip plus 37 codes derived
from a separate text dump in the issue, cross-checked byte-for-byte
against the community's own manual decode posted in the thread.

No temperature/pressure mapping: no capture in the issue pairs a raw code
with a numeric ground-truth reading, so only the validated raw code is
output for now.
2026-07-13 21:31:01 +02:00
Verstreubulator
430793a69c Add Fine Offset / Ecowitt WH52 soil moisture/temperature/EC decoder (#3602)
* Add Fine Offset / Ecowitt WH52 soil moisture/temperature/EC decoder
2026-07-13 20:47:30 +02:00
Benjamin Larsson
35fce5e440 Split Schrader SMD3MA4/NIS315G3 into two separate decoders
Per maintainer feedback, one decoder shouldn't emit multiple protocol
interpretations of the same payload under one model key:
https://github.com/merbanan/rtl_433/issues/1734#issuecomment-4957207247

schrader_SMD3MA4 and the new schrader_NIS315G3 share the same wire-format
decode (checksum, flags, id) via a common helper, differing only in
pressure scale (/5 vs /4) and model name. Both are enabled by default,
so a single physical transmission produces two output records; use -R
to select just one if that's undesirable.
2026-07-13 17:44:46 +02:00
Benjamin Larsson
96e3867ed5 Add Eco-Eye solar PV/grid current monitor decoder
FSK_PCM, 200us bit width, aa2dd4 sync word, byte-add checksum. Protocol
fully reverse-engineered by the community in
https://github.com/merbanan/rtl_433/issues/1757 (solved since 2021, but
never turned into a compiled decoder). Verified against the reporter's
real captures and cross-checked against their transmitter's own serial
console output, which matches digit for digit. Registered as protocol
351.
2026-07-12 22:12:22 +02:00
Paul Antaki
1ae8d45fea Add Govee-H5112 dual-probe thermometer decoder
Adapts the decoder from PR #3568 by Paul Antaki. Shares the Govee FSK
envelope reverse-engineered by Reece Neff for the H5059 (PR #3493):
sync word 2c 4c 4a, 128-byte XOR key, CRC-16/AUG-CCITT.

Both probe temperatures and humidity are packed into one 32-bit
little-endian word by the device's own firmware: 11 bits each for
probe1/probe2 (0.1 C/count, zero-anchored at -40 C) and 10 bits for
humidity (0.1%/count). Confirmed by dumping and disassembling the
H5112's FR8016HA firmware -- it contains a sensor-packing function
with this exact symmetric layout. Probe 2 is read directly as an
absolute value like probe 1: no per-device state, no wrap-count
tracking, no cold-start dependency.

Two frame types: msg_class 0x13 periodic report (~10 min interval,
full sensor data + 10-entry history buffer at ~1-minute intervals) and
msg_class 0x71 triggered status response (reply to gateway poll, same
sensor fields, no history).

Beyond the original PR, two guards make the separation from the other
Govee-family decoders structural rather than priority-dependent:
each msg_class must carry its exact documented payload length (57 or
28 bytes), and frames whose humidity decodes above 100% RH are
rejected -- the latter is the mirror of H5310's dec[9] == 0xff status
check, since a genuine H5310 status reply always decodes here as an
impossible 102.3% RH. Priority ordering (5, between H5310's 0 and
H5059's 10) remains as belt-and-braces only.

Verified against all 3 real captures from the companion
rtl_433_tests#505 PR -- two room-temperature devices (one with the
history buffer) and one fridge/freezer device (probe1 ~2.3 C, probe2
~-24.0 C) -- all match exactly. Also verified the H5310 status frames
that previously double-decoded as garbage H5112 records (102.3% RH)
under -y are now rejected by the humidity guard. Full local regression
suite: no new false positives.
2026-07-12 18:09:03 +02:00
Paul Antaki
9d96718e4c Add Govee-H5310 pool/spa thermometer decoder
Adapts the decoder from PR #3564 by Paul Antaki. The H5310 shares the
Govee FSK framing reverse-engineered by Reece Neff for the H5059 water
leak detector (PR #3493): sync word 2c 4c 4a, 128-byte XOR key, and
CRC-16/AUG-CCITT. This adds the four H5310-specific payload layouts:

- Temperature Update (LL=0x10): forced report or unit-change action
- Periodic Update (LL=0x3d): autonomous ~10-minute broadcast
- Status Reply (LL=0x1f): response to a gateway poll
- Ping (LL=0x1c): connectivity heartbeat, no temperature/battery data

Temperature formula T_C = (raw - 33168) / 10.0, confirmed against the
sensor's own display across two physical units (Pool and Spa) at
multiple temperatures. Wire encoding is always Celsius regardless of
the display unit setting.

Runs at default priority (0); H5059 runs at priority 10 so H5310 claims
shared-envelope frames first (see the companion commit for that fix).

Reviewed in the original PR by neffrw (the H5059 decoder's author).
Verified against all 7 real captures from the companion
rtl_433_tests#503 PR, across both physical units (Pool id_wire
0xf8a79cb2, Spa id_wire 0x71b09cb2) and all 4 frame types -- all match
exactly. Full local regression suite: no new false positives.
2026-07-12 16:48:21 +02:00
Steven Bontius
c9dcd8090f Add support for Watts WFHT-RF / WFHC-MASTERH&C-RF thermostats
Adapts the decoder from PR #3561 by Steven Bontius, who reverse
engineered the protocol (documented at
https://github.com/StevenBontius/watts-wfht-ha/blob/main/docs/WATTS_WFHT_RF_PROTOCOL.md)
for a newer, LCD-display generation of Watts underfloor heating
thermostat -- unrelated to the existing watts_thermostat.c decoder,
which targets an older ADEV-based generation with a completely
different protocol (PWM vs. this one's Manchester, different frame
layout, no CRC-16).

Verified against:
- The 2 worked examples in the protocol doc (independently recomputed
  both CRC-8 and CRC-16/CMS in Python against the documented
  parameters; both check out).
- All 3 real captures from the companion rtl_433_tests#502 PR (pairing,
  on, off) -- decode correctly, including the ~2 Hz pairing cadence,
  the A-B-A setpoint jitter around a real transition, and the 0.0 C
  setpoint on the "off" capture.

Full local regression suite: no new false positives.
2026-07-12 16:17:36 +02:00
Jacob Maxa
b4b5328226 Add support for TFA Dostmann 30.390X T/H sensors series
Adapts the decoder from PR #3446 by Jacob Maxa, who reverse engineered
the protocol for 5 related sensors in TFA's ID+ series (30.3901.02,
30.3902.02, 30.3905.02, 30.3906.02, 30.3908.02) and confirmed the
CRC-32 parameters with the maintainer.

Fixes found while investigating the PR (which is still open, blocked
on unaddressed review feedback):

- The preamble/length bounds check compared the found sync offset
  against a fixed bit-length constant instead of the actual row length.
  This wrongly rejected valid short frames (30/24 bytes) unless enough
  trailing bits happened to be present for the longest 36 byte variant,
  and never actually verified the full frame fit in the row before
  reading it. Now reads the length byte first and validates against
  the row length directly.
- The "model" data line used a runtime-built string; project convention
  (enforced by tests/symbolizer.py) requires a fixed string per model.
  ID-A0/ID-A6 share an identical frame layout, so they're merged into
  one switch case reporting both "model" lines guarded by DATA_COND
  (the same pattern used throughout fineoffset.c, oregon_scientific.c,
  and ~17 other decoders for same-layout model variants); ID-A3/A4/A5
  have genuinely different field sets, so each keeps its own data_make()
  call.
- Humidity lost its decimal digit through a plain int cast; kept as a
  scaled double like temperature.
- A stray nibble of the status byte had leaked into the printed id
  string; now a clean 4-byte/8-hex-char id.
- crc32_reveng() wasn't static, and used a #include "logger.h" +
  print_logf() instead of decoder_log().

No raw .cu8 captures were available to verify this decoder against
(checked both this repo and rtl_433_tests), but the PR's own doc-comment
included 6 worked examples (hand-transcribed hex for ID-A0/A3/A5 and
three sequential ID-A4 readings) that all validate against the CRC-32
above -- real device data, not fabricated. The 3 ID-A4 frames are also
internally consistent as a sliding window (each one's "current" reading
matches the next frame's "1 reading ago" value), further confirming the
field layout. Verified all 6 decode correctly, plus CRC-failure and
no-preamble rejection. Full local regression suite: no new false
positives.
2026-07-12 15:14:35 +02:00
Steven Walter
1b6a70123a Add support for EN2058 four probe temperature sensor
Adds the decoder from PR #3498, with fixes found by testing against
the real captures in rtl_433_tests#400 (all 6 captures decode exactly
matching their physical readouts):

- Fixes the 24-bit device ID: it was raw-pointer-cast into a native
  uint32_t, which byte-reverses it on little-endian platforms (the
  vast majority of rtl_433 users). Now extracted into a 3-byte buffer
  and combined manually, matching how the temperature fields (which
  already used ntohs() correctly) avoid the same class of bug.
- Fixes the dead "preamble not found" check: bitbuffer_search()
  returns unsigned, so `if (offset < 0)` could never be true. Now
  compares against the actual sentinel (bits_per_row[0]).
- Changes "mic" from a raw DATA_INT checksum byte to the standard
  DATA_STRING "CHECKSUM", matching every other decoder's convention.
- Fixes the checksum formula (0x56 + id bytes + sum of the 8
  temperature bytes) & 0xff, confirmed against all 6 real captures.
  Enabled by default now that it's verified reliable.
- Adds the previously-undecoded 8 bit sequence counter (sent as a
  duplicated byte, increments by 2 each repeat), gated on the row
  having enough bits so short/synthetic frames still decode.
- Uses add_bytes() and decoder_log() on checksum failure, matching
  sibling decoders (esun_en2053, ambientweather_wh31e).
- double -> float for the temperature accumulators.

Verified against all 6 real captures in rtl_433_tests#400 and the
full local regression suite (no new false positives).
2026-07-12 12:15:01 +02:00
David Woodhouse
2fa6593778 Add decoder for FSL Cricket Scoreboard Controller
FSK PCM with Manchester-encoded data, 10x repeated 72-bit blocks each
carrying a field ID and a 3-digit value validated by fixed position
markers. Cleans up brace/indent style and removes a dead assignment
from the original PR (merbanan/rtl_433#3443).

Verified against 18 real captures across three recording sessions
(field IDs 3, 5, 8, 14), all matching the ground truth documented in
the linked test-data repo's commit history (values stepping by 10 up
to 50).
2026-07-11 23:19:12 +02:00
Markus Dauberschmidt
dc1627bd73 Add decoder for Dickert MAHS433-01 garage door remote control
Reworks PR #3321 (closes #2983): fixes a buffer overflow where the
10-character dipswitch string had no room for its null terminator and
bled into the adjacent factory-code buffer on every real packet, changes
id to DATA_INT per review feedback, renames dipswitches/facswitches to
dipswitch/facswitch to match the existing convention in cardin.c, and
trims the bit extraction to the 36 valid bits instead of reading 1 bit
past the row length.

Verified against 6 real captures and all 12 BitBench codes from the
issue thread.
2026-07-11 22:25:01 +02:00
ProfBoc75
b50f724d1c Add support for SmarTire TPMS sensor, Vantage/Aston Martin DB9 protocol
Decoder for SmarTire TPMS sensors used on Aston Martin Vantage/DB9
vehicles (2005-2011), using OOK PCM framing with differential Manchester
coding and CRC-7 checksum validation.

Ported from merbanan/rtl_433#3072 (originally by Bruno OCTAU/ProfBoc75),
closes #3067.
2026-07-11 20:31:13 +02:00