{"id":29969460,"url":"https://github.com/peff74/esp32_tfa_drop_rain_gauge_decoder","last_synced_at":"2026-04-27T16:31:21.300Z","repository":{"id":307750302,"uuid":"1030197669","full_name":"peff74/ESP32_TFA_Drop_Rain_Gauge_Decoder","owner":"peff74","description":"About Arduino script for receiving and decoding the Drop Rain Gauge via 433 CC1101 - TFA Dostmann 30.3233.01 Regenmesser","archived":false,"fork":false,"pushed_at":"2026-04-23T23:54:40.000Z","size":11796,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-24T01:37:15.051Z","etag":null,"topics":["433","arduino","cc1101","dostmann","drop","esp32","gauge","rainmeter","rf","rx470-4","superheterodyne","tfa"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/peff74.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-08-01T08:40:53.000Z","updated_at":"2026-02-16T20:40:28.000Z","dependencies_parsed_at":"2025-08-18T01:07:43.904Z","dependency_job_id":"b4e9d31b-b859-4179-90e7-ff53c2656e22","html_url":"https://github.com/peff74/ESP32_TFA_Drop_Rain_Gauge_Decoder","commit_stats":null,"previous_names":["peff74/esp32_tfa_drop_rain_gauge_decoder"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/peff74/ESP32_TFA_Drop_Rain_Gauge_Decoder","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peff74%2FESP32_TFA_Drop_Rain_Gauge_Decoder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peff74%2FESP32_TFA_Drop_Rain_Gauge_Decoder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peff74%2FESP32_TFA_Drop_Rain_Gauge_Decoder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peff74%2FESP32_TFA_Drop_Rain_Gauge_Decoder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/peff74","download_url":"https://codeload.github.com/peff74/ESP32_TFA_Drop_Rain_Gauge_Decoder/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/peff74%2FESP32_TFA_Drop_Rain_Gauge_Decoder/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32345802,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-26T23:26:28.701Z","status":"online","status_checked_at":"2026-04-27T02:00:06.769Z","response_time":128,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["433","arduino","cc1101","dostmann","drop","esp32","gauge","rainmeter","rf","rx470-4","superheterodyne","tfa"],"created_at":"2025-08-04T04:07:59.845Z","updated_at":"2026-04-27T16:31:21.291Z","avatar_url":"https://github.com/peff74.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# TFA Drop Rain Gauge Decoder (30.3233.01)\n - This is a TFA Drop Rain Gauge 30.3233.01 decoder script for Arduino\n - The 30.3233.01 is a 433MHz wireless rain gauge with 0.254mm resolution\n - Decodes 64-bit PWM messages with CRC-8 validation\n - Works with ESP32 and similar boards\n - **Two receiver options**: RX470-4 superheterodyne or CC1101 transceiver\n\n![TFA Rain Gauge logo](https://github.com/peff74/ESP32_TFA_Drop_Rain_Gauge_Decoder/blob/main/TFA_Regenmesser.jpeg)\n![TFA Rain Gauge logo](https://github.com/peff74/ESP32_TFA_Drop_Rain_Gauge_Decoder/blob/main/RF433.jpg)\n![TFA Rain Gauge logo](https://github.com/peff74/ESP32_TFA_Drop_Rain_Gauge_Decoder/blob/main/cc1101.jpg)\n\n\n## Arduino script features\n - Real-time 433MHz RF signal decoding\n - Hardware interrupt-based signal capture\n - Multi-stage message validation (Prefix → Constant → CRC-8)\n - Duplicate message validation (200ms window)\n - PWM pulse decoding with timing tolerance\n - Non-blocking operation\n - IRQ overload protection\n - Reception statistics tracking\n - So that even beginners (like me) can understand 433MHz decoding\n\n## Receiver Comparison\n\n### Option 1: RX470-4 Superheterodyne (~$2)\n**Pros:**\n - Very cheap\n - Simple wiring (3 pins)\n - No library required\n\n**Cons:**\n - **Requires filter circuit** (100nF + 1kΩ)\n - High noise IRQ rate (5000-8000/s without filter)\n - Lower sensitivity\n - Antenna critical (exactly 17.3cm)\n\n### Option 2: CC1101 Transceiver (~$3-5)\n**Pros:**\n - **Excellent selectivity** - virtually no noise IRQs\n - **No filter circuit needed**\n - Much better sensitivity\n - Digital RSSI readings\n - Adjustable bandwidth and data rate\n - More reliable reception\n\n**Cons:**\n - Slightly more expensive\n - More complex wiring (SPI)\n - Requires CC1101 library\n\n**Recommendation:** Use CC1101 for production use. The improved signal quality and no filter requirement make it worth the small extra cost.\n\n## How does it work\n\n**RF Signal Reception**\n\n*With RX470-4:*\nThe receiver outputs digital pulses on the DATA pin.\nEvery signal change triggers a hardware interrupt.\n\n*With CC1101:*\nThe CC1101's GDO0 pin outputs demodulated ASK/OOK data.\nHardware interrupt on CHANGE captures signal edges with minimal noise.\n\n    void IRAM_ATTR handleRFInterrupt() {\n        irqCounter = irqCounter + 1;\n        unsigned long currentTime = micros();\n        unsigned long duration = currentTime - lastTime;\n        // Store timing for PWM decoding\n\n**PWM Decoding**\nThe rain gauge uses PWM encoding where pulse width determines bit value:\n - **Bit 0**: Short pulse (250µs) + Long gap (500µs)  \n - **Bit 1**: Long pulse (500µs) + Short gap (250µs)\n - **Sync**: Long pause (\u003e1500µs) marks message start\n\n*searchDecodeAndValidateData()*\n\n    // PWM detection with tolerance\n    if (abs((int)pulse - PULSE_SHORT) \u003c TOLERANCE \u0026\u0026 \n        abs((int)gap - PULSE_LONG) \u003c TOLERANCE) {\n        bit = false;  // Short pulse = 0\n    } else if (abs((int)pulse - PULSE_LONG) \u003c TOLERANCE \u0026\u0026 \n               abs((int)gap - PULSE_SHORT) \u003c TOLERANCE) {\n        bit = true;   // Long pulse = 1\n    }\n\n**Message Format (64 bits)**\nThe decoded message contains weather station data:\n\n    +--------+--------+--------+--------+--------+--------+--------+--------+\n    |  Byte 0|  Byte 1|  Byte 2|  Byte 3|  Byte 4|  Byte 5|  Byte 6|  Byte 7|\n    +--------+--------+--------+--------+--------+--------+--------+--------+\n    |PPPPDDDD|DDDDDDDD|DDDDDDDD|BCUUXXXX|RRRRRRRR|CCCCCCCC|SSSSSSSS|MMMMMMMM|\n    +--------+--------+--------+--------+--------+--------+--------+--------+\n    \n    P = Prefix (0x3)\n    D = Device ID (20 bits)\n    B = Battery Low flag\n    C = Device Reset flag  \n    U = Unknown\n    X = TX Counter (4 bits)\n    R = Rain Counter LSB\n    C = Constant (0xAA)\n    S = Rain Counter MSB\n    M = CRC-8 checksum\n\n**Duplicate Message Validation**\nThe rain gauge transmits each message twice within ~50-150ms.\nThe decoder validates duplicates to ensure data integrity:\n\n*validateDuplicate()*\n\n    // Store first message, wait for duplicate\n    if (!hasPendingMessage) {\n        memcpy(pendingMessage.data, data, MESSAGE_BYTES);\n        pendingMessage.timestamp = currentTime;\n        hasPendingMessage = true;\n        return false;  // Wait for duplicate\n    }\n    \n    // Validate duplicate matches\n    if (memcmp(pendingMessage.data, data, MESSAGE_BYTES) == 0) {\n        successfulDuplicates++;\n        return true;  // Message validated!\n    }\n\n**200ms Timeout:**\n - If no duplicate arrives within 200ms → message discarded\n - If different message arrives → both discarded, new becomes first\n - Only matching duplicates are accepted\n\n## Message Decoding Example\n\n**Raw Data**: `3E42A800FEAAFF5E`\n\n**Bit Layout**:\n```\n00111110 01000010 10101000 00000000 11111110 10101010 11111111 01011110\nPPPPDDDD DDDDDDDD DDDDDDDD BCUUXXXX RRRRRRRR CCCCCCCC SSSSSSSS MMMMMMMM\n```\n\n**Decoded Values**:\n\n*Byte 0 (0x3E)*: Prefix=0x3 ✓, Device-ID High=0xE  \n*Byte 1 (0x42)*: Device-ID Middle=0x42  \n*Byte 2 (0xA8)*: Device-ID Low=0xA8  \n**→ Device-ID**: 0xE42A8 = 935,592\n\n*Byte 3 (0x00)*: Battery=OK, Reset=No, TX-Counter=0  \n*Byte 4 (0xFE)*: Rain Counter LSB=254  \n*Byte 5 (0xAA)*: Constant=0xAA ✓  \n*Byte 6 (0xFF)*: Rain Counter MSB=255  \n**→ Rain Counter**: (255 \u003c\u003c 8) + 254 = 65,534\n\n*Byte 7 (0x5E)*: CRC-8 checksum\n\n**Rain Calculation**:\n```\nRaw Counter: 65,534\nOffset: 65,526 (RAIN_COUNTER_OFFSET)\nReal Tips: 65,534 - 65,526 = 8 tips\nRainfall: 8 × 0.254 mm = 2.032 mm\n```\n\n**Multi-Stage Validation**\nFast validation prevents CPU overload from invalid signals:\n\n*quickValidation()*\n\n    // Stage 1: Quick prefix check (\u003c 1µs)\n    uint8_t prefix = (data[0] \u003e\u003e 4) \u0026 0x0F;\n    if (prefix != EXPECTED_PREFIX) return false;\n    \n    // Stage 2: Constant check\n    if (data[5] != EXPECTED_CONSTANT) return false;\n\n*validateCRC()*\n\n    // Stage 3: CRC-8 validation (only if stages 1+2 pass)\n    uint8_t computed_crc = lfsr_digest8_reflect(data, 7, 0x31, 0xF4);\n    return (computed_crc == data[7]);\n\n**CRC-8 Algorithm Details**\nThe rain gauge uses a reflected LFSR CRC-8:\n - **Generator Polynomial**: 0x31 (x⁸ + x⁵ + x⁴ + 1)\n - **Initial Key**: 0xF4  \n - **Reflection**: Bytes processed backwards (6→0), bits LSB to MSB\n\n*lfsr_digest8_reflect()*\n\n    // Process bytes from end to start (reflected)\n    for (int k = bytes - 1; k \u003e= 0; --k) {\n        uint8_t data = message[k];\n        // Process bits from LSB to MSB (reflected)\n        for (int i = 0; i \u003c 8; ++i) {\n            if ((data \u003e\u003e i) \u0026 1) {\n                sum ^= key;\n            }\n            // LFSR shift with generator feedback\n            if (key \u0026 0x80) {\n                key = ((key \u003c\u003c 1) \u0026 0xFF) ^ gen;\n            } else {\n                key = (key \u003c\u003c 1) \u0026 0xFF;\n            }\n        }\n    }\n\n**CRC Verification for Example Data**:\nInput: `3E 42 A8 00 FE AA FF` (bytes 0-6)  \nProcessing order: FF → AA → FE → 00 → A8 → 42 → 3E  \nCalculated CRC: `0x5E`  \nReceived CRC: `0x5E` ✓\n\n**Rain Calculation**\nThe 16-bit rain counter has an offset that must be subtracted:\n\n*calculateRealTips()*\n\n    int realTips = rainCounter - RAIN_COUNTER_OFFSET;  // 65526\n    if (realTips \u003c 0) {\n        // Handle counter overflow\n        realTips = rainCounter + (65536 - RAIN_COUNTER_OFFSET);\n    }\n    float rainMM = realTips * RAIN_TIP_TO_MM;  // 0.254mm per tip\n\n\n\n\n## Protocol Summary\n\n**Signal Processing Flow:**\n1. RF receiver detects 433MHz signal changes\n2. Hardware interrupt captures pulse/gap timings\n3. Sync pulse (\u003e1500µs) triggers decoding start\n4. 64 pulse/gap pairs decoded to bits (MSB first)\n5. Multi-stage validation: Duplicate → Prefix → Constant → CRC-8\n6. Rain counter converted to real tips and mm rainfall\n7. Status flags (battery, reset, TX counter) extracted\n\n\n## Hardware Setup\n\n### Option 1: RX470-4 Superheterodyne\n\n**Required Components:**\n - ESP32 development board\n - RX470-4 433MHz receiver module  \n - 17.3cm wire antenna\n - **Filter circuit required!**\n\n**Connections:**\n    \n    RX470-4    →    ESP32\n    --------         -----\n    VCC        →    3.3V\n    GND        →    GND  \n    DATA       →    GPIO 22\n    ANT        →    17.3cm wire\n\n**⚠️ Filter Circuit Required**\nWithout filtering, RF noise can cause IRQ overload (\u003e8000 IRQ/s):\n```\nRX470-4 DATA ──┬─── 1  kΩ ───┬─── ESP32 GPIO 22\n               │             │\n           100nF C           │\n               │             │\n               └─────────────┴─── GND\n```\n\n**Normal vs. Overloaded IRQ rates:**\n\n    IRQ/s: 150-1500    ← Normal operation (with filter)\n    IRQ/s: 8500        ← Overloaded! Add filter circuit\n\n### Option 2: CC1101 Transceiver (Recommended)\n\n**Required Components:**\n - ESP32 development board\n - CC1101 433MHz transceiver module\n - Wire antenna (optional - module has built-in)\n\n**Connections (SPI):**\n    \n    CC1101     →    ESP32\n    --------         -----\n    VCC        →    3.3V\n    GND        →    GND\n    SCK        →    GPIO 18\n    MISO       →    GPIO 19\n    MOSI       →    GPIO 23\n    CSN        →    GPIO 5\n    GDO0       →    GPIO 27\n\n**CC1101 Configuration:**\n    \n    cc1101.setMHZ(433.92);              // Frequency\n    cc1101.setDataRate(2000);           // 2 kBaud\n    cc1101.setRxBW(RX_BW_203_KHZ);      // Bandwidth\n    cc1101.setModulation(ASK_OOK);      // ASK/OOK modulation\n    cc1101.setRx();                     // Set to RX mode\n\n**Library Required:**\n```cpp\n#include \u003cCC1101_ESP_Arduino.h\u003e\n```\n\n**⚠️ Important: Modified Library Needed**\n\nFor RSSI functionality, you need the modified version with RSSI support:\n- **GitHub PR**: https://github.com/wladimir-computin/CC1101-ESP-Arduino/pull/11\n- Standard library does NOT include `getRSSI()` function\n- Clone the PR branch or wait for merge into main library\n\n**Installation:**\n```bash\n# Clone modified library to Arduino/libraries/\ngit clone https://github.com/peff74/CC1101-ESP-Arduino.git\n# Or download as ZIP and install manually\n```\n\nWithout this modification, remove all `cc1101.getRSSI()` calls from the code.\n\n**IRQ Performance Comparison:**\n\n    RX470-4 (no filter):  5000-8500 IRQ/s\n    RX470-4 (with filter): 150-1500 IRQ/s\n    CC1101:                       0 IRQ/s  ← Clean signal!\n\n**Additional CC1101 Benefits:**\n - Real-time RSSI measurements (signal strength in dBm)\n - No filter components needed\n - Better range and sensitivity\n - Cleaner data output\n\n## Output Examples\n\n**With CC1101:**\n\n    === Rain Gauge Data ===\n    Signal RSSI: -67 dBm\n    Received Bits: 64\n    Raw: 3E42A808E7AA005E\n    Bits: 00111110 01000010 10101000 00001000 11100111 10101010 00000000 01011110\n          CCCCIIII IIIIIIII IIIIIIII BCUUXXXX RRRRRRRR CCCCCCCC SSSSSSSS MMMMMMMM\n    Device ID: 0xE42A8 (934568)\n    Reset: NO\n    TX Counter: 0x8 (8)\n    Battery: OK\n    Rain Counter 16-Bit: 231\n    Real Tips: 241\n    Precipitation: 61.214 mm\n    CRC: computed=0x5E, received=0x5E (OK)\n    IRQ/s: 87\n    \n    --- Reception Statistics ---\n    Total Received: 156\n    Successful Duplicates: 152 (97.4%)\n    Duplicate Timeouts: 4 (2.6%)\n    Different Messages: 0\n\n**Duplicate Validation Messages:**\n\n    [MSGS]: First message received, waiting 200ms for duplicate...\n    [MSGS]: Duplicate received after 78ms - message valid!\n\n    [FAIL]: Duplicate timeout after 201ms - discarding message\n\n## Troubleshooting\n\n### RX470-4 Issues\n\n**No data received:**\n - Check antenna length (exactly 17.3cm for 433MHz)\n - Verify wiring connections\n - Add/check filter circuit\n - Move closer to rain gauge (max ~100m range)\n\n**High IRQ count (\u003e5000/s):**\n - **Add filter circuit** between receiver and ESP32\n - Move away from RF interference sources\n - Check receiver module quality\n\n### CC1101 Issues\n\n**No data received:**\n - Verify SPI connections (SCK, MISO, MOSI, CS)\n - Check CC1101 library installed correctly (see modified library requirement above!)\n - Verify 3.3V power supply (not 5V!)\n - Check GDO0 connection for interrupt\n - Test with `cc1101.getVersion()` in setup\n\n**RSSI not working:**\n - Make sure you're using the modified library from PR #11\n - Standard library does not include `getRSSI()` function\n - See library installation section above\n\n**Low RSSI (\u003c-90 dBm):**\n - Move closer to rain gauge\n - Check antenna connection\n - Verify frequency setting (433.92 MHz)\n\n**Good RSSI but no decode:**\n - Adjust RX bandwidth if needed\n - Check data rate setting (2000 baud)\n - Verify ASK/OOK modulation selected\n\n## Files in Repository\n\n - `TFA_Drop_RX470.ino` - Original version with RX470-4 receiver\n - `TFA_Drop_CC1101.ino` - New version with CC1101 transceiver\n - `README.md` - This documentation\n\n## License \u0026 Credits\n\nOriginal decoder logic and protocol analysis by peff74  \nCC1101 integration and improvements added 2025\n\nFeel free to use and modify for your own projects!\n\n![Badge](https://hitscounter.dev/api/hit?url=https%3A%2F%2Fgithub.com%2Fpeff74%2FESP32_TFA_Drop_Rain_Gauge_Decoder\u0026label=Hits\u0026icon=github\u0026color=%23198754\u0026message=\u0026style=flat\u0026tz=UTC)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpeff74%2Fesp32_tfa_drop_rain_gauge_decoder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpeff74%2Fesp32_tfa_drop_rain_gauge_decoder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpeff74%2Fesp32_tfa_drop_rain_gauge_decoder/lists"}