Trial port of the rtl_433 Library for use with OpenMQTTGateway on a ESP32 and a CC1101 Transceiver
Trial port of the rtl_433 Library for use with OpenMQTTGateway on a ESP32 and a CC1101 Transceiver
This is an attempt at creating an Arduino library for use on ESP32 boards with a CC1101 transceiver or SX127X Transceivers with the device decoders from the rtl_433 package. And be available for use with openMQTTGateway as an available module.
Architecture, task ownership, callback context, lifecycle, and resource notes are documented in docs/ARCHITECTURE.md. The upstream refresh procedure is documented in docs/UPSTREAM.md.
Inspiration for this came from the ESPiLight effort. Kudos to puuu for this, and the awesome package.
This is the LILYGO® LoRa32 V2.1_1.6.1 433Mhz board running OpenMQTTGateway.
The initial port implements only enables a subset of the available modulations and device decoders, and is limited to devices I have access to and can test with.
OOK_MC_ZEROBIT
OOK_PULSE_DMC
OOK_PULSE_MANCHESTER_ZEROBIT
OOK_PULSE_NRZS
OOK_PULSE_PCM
OOK_PULSE_PIWM_DC
OOK_PULSE_PPM
OOK_PULSE_PWM
OOK_PULSE_PWM_OSV1
OOK_PULSE_RZFSK_PULSE_MANCHESTER_ZEROBIT
FSK_PULSE_PCM
FSK_PULSE_PWMPlease note that FSK or OOK demodulation mode can not be used simultaneously, due the usage of the receiver chipset's signal demodulator.
The bundled decoders were refreshed on August 14, 2026 from rtl_433 development
snapshot 25.12-346-g91b2ebdb, commit 91b2ebdb.
…The current OOK registration contains 223 protocol decoders.
…The current FSK registration contains 153 protocol decoders.
These are the sensors that are part of my personal collection, and can confirm that they work correctly. Other sensors devices are on a best effort basis as I have no method to test and confirm functionality.
Acurite Tower - Acurite 592TXR Temp/Humidity, 592TX Temp, 5n1 Weather Station, 6045 Lightning, 899 Rain, 3N1, Atlas
LaCrosse-TX141Bv3 - LaCrosse TX141-Bv2, TX141TH-Bv2, TX141-Bv3, TX141W, TX145wsdth, (TFA, ORIA) sensor
Acurite-986 - Acurite 986 Refrigerator / Freezer Thermometer
Skylink_HA-434TL_motion - Skylink HA-434TL motion sensor
FineOffSet WH51Datasheet for the CC1101 board I'm using
This is the Heltec SX127X board I used for development. I used the 433 Mhz Board with the SX127X chipset.
This is the LILYGO® LoRa32 V2.1_1.6.1 433 board I used for development. I used the 433 Mhz Board with the SX127X chipset.
When your purchasing one of these, please watch out for similar boards that do not use the SX127X chipset. These others boards will not work, as the required receiver mode is not available in the chipset.
This is the AI-Thinker R01 - SX1278 module I used for development. I used the Ra-01 433 Mhz Board
This is the ESP32 DOIT DevKit V1 board I used for development.
Wiring for ESP32 DOIT DevKit V1 and AI-Thinker R01 - SX1278
The library supports multiple frequency bands including 433 MHz, 868 MHz, and 915 MHz. The receive frequency can be configured using the RF_MODULE_FREQUENCY build flag in your platformio.ini file.
The transceiver modules (CC1101, SX1276, SX1278) support multiple frequency bands depending on the hardware variant:
To set a custom frequency, add the RF_MODULE_FREQUENCY build flag to your environment in platformio.ini:
build_flags =
'-DRF_MODULE_FREQUENCY=868.30' ; Set frequency to 868.30 MHzExamples:
'-DRF_MODULE_FREQUENCY=433.92' ; 433 MHz (default)
'-DRF_MODULE_FREQUENCY=868.30' ; 868 MHz (common for EU sensors)
'-DRF_MODULE_FREQUENCY=915.00' ; 915 MHz (US ISM band)Note: Make sure your hardware supports the frequency band you want to use. Many LoRa modules are available in different frequency variants (e.g., 433 MHz, 868 MHz, 915 MHz versions). The frequency must match your hardware's capabilities and the sensors you want to receive.
For a complete example, see the esp32_heltec_915 environment in examples/OOK_Receiver/platformio.ini.
The library supports two callback interfaces:
setCallback(...) - receives JSON payloads for successfully decoded signals.setRawPulsesCallback(...) - receives raw pulse/gap timing for every captured signal, including signals that do not match a built-in decoder.typedef void (*rtl_433_raw_pulse_cb)(
const int* pulse_us,
const int* gap_us,
unsigned int num_pulses,
unsigned long duration_us,
int rssi
);Registering callbacks:
rf.setCallback(rtl_433_Callback, messageBuffer, JSON_MSG_BUFFER);
rf.setRawPulsesCallback(rtl_433_RawCallback);Raw pulse pointers are valid only during the callback. Copy any data you need to keep.
Details are here
OpenMQTTGateway - https://github.com/1technophile/OpenMQTTGateway
Acurite 5n1 to Weather Services Forwarder - https://github.com/shchuko/acurite-bridge
To determne that a signal is available for reception, the library watches the current RSSI reported by the transceiver module and when it crosses a predetermined RSSI threshold it enables the signal receiver function. End of signal is determined when the signal drops below the predetermined RSSI threshold for a minimum of 150,000 micro seconds.
The RSSI Threshold for signal detection is automatically determined based on the average RSSI signal level received aka RSSI floor level with a delta ( RSSI_THRESHOLD ) added to it. At startup, reception remains disabled while the first RSSI_INITIAL_SAMPLES readings are collected, preventing the initial MINRSSI value from creating one long false signal. The resulting floor and threshold are logged when reception is enabled. Subsequent averages use RSSI_SAMPLES.
For background see section 2.1.3.2. of SX127X Data sheet
To tune the SX127X OOK RSSI FIXED Threshold two values are used to determine if the threshold needs to be increased or decreased. The first is the noise received between signals. If the number of noise bits received between signals is greater than 100, then the threshold is incremented. Second is the unparsed signals. If an unparsed signal is received, but it has less than 20 pulses, the threshold is decremented.
The first approach is what is recommended in the SX127X datasheet, and the second is a control to lower the threshold if it is too high and incomplete signals are received.
…DISABLERSSITHRESHOLD does not disable the RSSI gate. It fixes the gate at
MINRSSI (default -82 dBm). If the receiver reports RSSI values below that
level, no signal will pass the gate and the library may appear silent. Override
MINRSSI with a value below the measured idle RSSI, or leave automatic RSSI
threshold selection enabled.
When no signals are reported, first verify radio initialization and register
readback, then observe the idle RSSI and confirm the configured threshold is
below the RSSI reached during a transmission. If the radio's data pin toggles
but the library reports no events, also check MINIMUM_PULSE_LENGTH and
MINIMUM_SIGNAL_LENGTH against the protocol being received.
CC1101 OOK performance can depend on the receiver module, local noise, and transmitter frequency error. The bandwidth and AGC registers can be overridden without modifying the library source. The defaults remain the broad rtl_433_ESP profile for compatibility.
Testing 345 MHz Vivint sensors at one installation showed that a narrower
162.5 kHz receive bandwidth with AGCCTRL2=0x84, AGCCTRL1=0x40, and
AGCCTRL0=0xA0 reduced zero-decode signals and produced more complete signal
captures than the broad default profile. Use these values as a starting point,
not a universal preset: antenna, module crystal tolerance, interference, and
sensor frequency offset can change the best result. The dedicated
CC1101 tuning example can run the search and
comparison suites unattended to validate the profile locally. The complete
method and results are recorded in
CC1101 Vivint tuning results.
build_flags =
-DRF_MODULE_FREQUENCY=345.00
-DCC1101_RX_BANDWIDTH=162.5
-DCC1101_AGCCTRL2=0x84
-DCC1101_AGCCTRL1=0x40
-DCC1101_AGCCTRL0=0xA0LOG_LEVEL also controls the library's logprintf and alogprintf output.
Set -DLOG_LEVEL=0 (ArduinoLog's silent level) to suppress that diagnostic
output completely.
The decoder task runs on core 0 for single-core ESP32 targets and core 1 for
dual-core targets. ESP32-C5 custom SPI pin configurations use FSPI, matching
the ESP32-C3 and ESP32-S3 configuration. PlatformIO support for the C5 depends
on the selected Espressif platform and Arduino core; the library does not
require a repository-wide compiler-warning override or custom linker flags.
rtl_433_ESP automatically discovers a Vivint sensor's 16-bit seed after collecting enough packets with distinct counters. A known seed can instead be provided at compile time to decrypt packets immediately:
build_flags =
'-DVIVINT_SEEDS="0016-0357157=e4d8,0016-0345744=1e35,0016-0357170=c283"'Each entry uses the Vivint TXID=hexseed format. Separate multiple sensors
with commas and keep the complete definition single-quoted in platformio.ini.
When no matching configured seed is present, automatic discovery remains
enabled.
Seed diagnostics are enabled by default. They report seed, decode_status,
seed_data_count, seed_data_required, and seed_candidate_count. To omit
these fields from decoded messages, add:
build_flags =
'-DOUTPUT_VIVINT_DECODE=0'Seed discovery can be tuned for memory use and confidence. The required sample count must not exceed the cache size:
build_flags =
'-DVIVINT_MAX_SENSORS=32'
'-DVIVINT_CACHED_COUNTERS=8'
'-DVIVINT_SEED_DATA_REQUIRED=6'ONBOARD_LED ; GPIO pin to toggle during signal reception ( Typically onboard LED )No open issues yet, or sync has not completed.