|
| 1 | +# GitHub Copilot Instructions for BresserWeatherSensorReceiver |
| 2 | + |
| 3 | +## Project Overview |
| 4 | + |
| 5 | +**BresserWeatherSensorReceiver** is an Arduino library for receiving and decoding 868 MHz wireless data from Bresser weather sensors using ESP32, ESP8266, or RP2040 microcontrollers with RF transceivers (CC1101, SX1276/RFM95W, SX1262, or LR1121). |
| 6 | + |
| 7 | +### Key Responsibilities |
| 8 | +- Receive and decode RF messages from multiple Bresser sensor types (5-in-1, 6-in-1, 7-in-1, 8-in-1 weather stations, lightning sensors, water leakage sensors, etc.) |
| 9 | +- Support multiple simultaneous sensors with ID filtering and slot management |
| 10 | +- Provide post-processing for rain gauge statistics and lightning detection |
| 11 | +- Integrate with MQTT, WiFi, OLED displays, SD cards, and Home Assistant |
| 12 | + |
| 13 | +## Architecture |
| 14 | + |
| 15 | +### Core Classes |
| 16 | + |
| 17 | +| Class | File | Purpose | |
| 18 | +|-------|------|---------| |
| 19 | +| `WeatherSensor` | `WeatherSensor.h/.cpp` | Main receiver class - RF reception, message decoding, multi-sensor management | |
| 20 | +| `RainGauge` | `RainGauge.h/.cpp` | Rain statistics - hourly/daily/weekly/monthly accumulation, overflow handling | |
| 21 | +| `Lightning` | `Lightning.h/.cpp` | Lightning strike counting, hourly history, post-processing | |
| 22 | +| `InitBoard` | `InitBoard.h/.cpp` | Board-specific initialization for 15+ ESP32/ESP8266 variants | |
| 23 | + |
| 24 | +### Key Design Patterns |
| 25 | + |
| 26 | +1. **Union-Based Memory Efficiency**: Sensor data stored in unions to minimize memory footprint |
| 27 | +2. **Conditional Compilation**: Features selectable via `WeatherSensorCfg.h` macros |
| 28 | +3. **Circular History Buffers**: 60-minute history for rain/lightning with wraparound |
| 29 | +4. **Preferences Storage**: Flash-based persistence for sensor configs, rain/lightning history |
| 30 | +5. **Slot-Based Multi-Sensor**: Dynamic `std::vector<Sensor>` for managing multiple sensors |
| 31 | +6. **Decoder Chain**: Try decoders in order (7-in-1 → 6-in-1 → 5-in-1 → Lightning → Leakage) until success |
| 32 | + |
| 33 | +## Coding Conventions |
| 34 | + |
| 35 | +### Naming Conventions |
| 36 | +- **Classes**: `CamelCase` (e.g., `WeatherSensor`, `RainGauge`) |
| 37 | +- **Functions/Methods**: `camelCase` (e.g., `getMessage()`, `getData()`) |
| 38 | +- **Variables**: `snake_case` (e.g., `sensor_id`, `wind_speed_ms`) |
| 39 | +- **Constants/Macros**: `UPPER_SNAKE_CASE` (e.g., `NUM_SENSORS`, `BRESSER_5_IN_1`) |
| 40 | +- **Private Members**: No specific prefix convention |
| 41 | + |
| 42 | +### File Organization |
| 43 | +``` |
| 44 | +src/ |
| 45 | +├── WeatherSensor.h/.cpp # Core receiver & decoder orchestration |
| 46 | +├── WeatherSensorCfg.h # User configuration (pins, sensors, decoders) |
| 47 | +├── WeatherSensorConfig.cpp # Runtime configuration via JSON |
| 48 | +├── WeatherSensorDecoders.cpp # Protocol decoders (5/6/7-in-1, Lightning, Leakage) |
| 49 | +├── WeatherUtils.h/.cpp # Utility functions (dew point, wind chill, etc.) |
| 50 | +├── RainGauge.h/.cpp # Rain statistics module |
| 51 | +├── Lightning.h/.cpp # Lightning post-processing module |
| 52 | +└── InitBoard.h/.cpp # Board initialization |
| 53 | +
|
| 54 | +examples/ |
| 55 | +├── BresserWeatherSensorBasic/ # Simple receive & print |
| 56 | +├── BresserWeatherSensorMQTT/ # MQTT integration |
| 57 | +├── BresserWeatherSensorMQTTCustom/ # Advanced MQTT with local copy of library |
| 58 | +└── [12 other examples] |
| 59 | +
|
| 60 | +test/ |
| 61 | +└── src/ # CppUTest unit tests |
| 62 | +``` |
| 63 | + |
| 64 | +### Header File Structure |
| 65 | +Every source file must include: |
| 66 | +1. **File header comment block** with: |
| 67 | + - File name and purpose |
| 68 | + - Project URL: `https://github.com/matthias-bs/BresserWeatherSensorReceiver` |
| 69 | + - Credits/references to original work |
| 70 | + - MIT License text |
| 71 | + - Detailed history log with dates and changes |
| 72 | + - Author: Matthias Prinke |
| 73 | +2. **Include guards** (not `#pragma once`) |
| 74 | +3. **Arduino.h include** for Arduino types |
| 75 | +4. **Doxygen-style comments** for public API |
| 76 | + |
| 77 | +### Documentation Standards |
| 78 | +- Use `///` for Doxygen comments on functions/classes |
| 79 | +- Use `//` for inline explanations |
| 80 | +- Add `@brief`, `@param`, `@return` tags for public methods |
| 81 | +- Reference rtl_433 project sources when applicable |
| 82 | +- Document protocol details and sensor quirks extensively |
| 83 | + |
| 84 | +### Code Style |
| 85 | +- **Indentation**: 4 spaces (no tabs) |
| 86 | +- **Braces**: Opening brace on same line for functions/classes |
| 87 | +- **Line Length**: No strict limit, but keep readable (~100-120 chars preferred) |
| 88 | +- **Comments**: Extensive inline documentation explaining RF protocols, sensor behavior, edge cases |
| 89 | +- **Debug Output**: Use `log_d()`, `log_i()`, `log_w()`, `log_e()` macros (ESP32/ESP8266) |
| 90 | +- **Conditional Features**: Wrap optional features in `#ifdef FEATURE_NAME` |
| 91 | + |
| 92 | +### Error Handling |
| 93 | +- Return `DecodeStatus` enum from decoders (e.g., `DECODE_OK`, `DECODE_DIG_ERR`, `DECODE_CHK_ERR`) |
| 94 | +- Use validation flags in structs (e.g., `temp_ok`, `humidity_ok`, `wind_ok`) |
| 95 | +- Check sensor startup flag to prevent false rain/lightning counts after battery replacement |
| 96 | +- Validate CRC/checksums using `lfsr_digest16()` or `crc16()` |
| 97 | + |
| 98 | +## Common Patterns & Idioms |
| 99 | + |
| 100 | +### Conditional Compilation |
| 101 | +Use macros in `WeatherSensorCfg.h` to enable/disable features: |
| 102 | +```cpp |
| 103 | +#define BRESSER_5_IN_1 // Enable 5-in-1 decoder |
| 104 | +#define BRESSER_6_IN_1 // Enable 6-in-1 decoder |
| 105 | +#define BRESSER_7_IN_1 // Enable 7-in-1 decoder |
| 106 | +#define BRESSER_LIGHTNING // Enable lightning decoder |
| 107 | +#define LIGHTNING_USE_PREFS // Store lightning history in flash |
| 108 | +``` |
| 109 | +
|
| 110 | +### Preferences API (Flash Storage) |
| 111 | +```cpp |
| 112 | +#include <Preferences.h> |
| 113 | +Preferences preferences; |
| 114 | +preferences.begin("namespace", false); // false = read/write |
| 115 | +uint32_t value = preferences.getUInt("key", default_value); |
| 116 | +preferences.putUInt("key", value); |
| 117 | +preferences.end(); |
| 118 | +``` |
| 119 | + |
| 120 | +### Rain Gauge Usage Pattern |
| 121 | +```cpp |
| 122 | +RainGauge rainGauge; |
| 123 | +rainGauge.reset(); // Reset all statistics |
| 124 | +rainGauge.update(timestamp, rain_mm, startup_flag); |
| 125 | +float hourly = rainGauge.pastHour(); |
| 126 | +float daily = rainGauge.currentDay(); |
| 127 | +``` |
| 128 | + |
| 129 | +### Lightning Detection Pattern |
| 130 | +```cpp |
| 131 | +Lightning lightning; |
| 132 | +lightning.reset(); |
| 133 | +lightning.update(timestamp, strike_count, distance_km, startup_flag); |
| 134 | +uint8_t strikes_past_hour = lightning.pastHour(); |
| 135 | +``` |
| 136 | + |
| 137 | +### Multi-Sensor Slot Management |
| 138 | +```cpp |
| 139 | +// Add sensor configuration |
| 140 | +std::vector<uint32_t> sensor_ids = {0x39582376}; |
| 141 | +weatherSensor.setSensorsCfg(sensor_ids); |
| 142 | + |
| 143 | +// Get data with timeout |
| 144 | +int decode_status = weatherSensor.getData(RX_TIMEOUT, DATA_COMPLETE); |
| 145 | +if (decode_status == DECODE_OK) { |
| 146 | + for (size_t i = 0; i < weatherSensor.sensor.size(); i++) { |
| 147 | + if (weatherSensor.sensor[i].valid) { |
| 148 | + uint32_t id = weatherSensor.sensor[i].sensor_id; |
| 149 | + // Process sensor data... |
| 150 | + } |
| 151 | + } |
| 152 | +} |
| 153 | +``` |
| 154 | + |
| 155 | +### Decoder Implementation |
| 156 | +Decoders should: |
| 157 | +1. Check message length: `if (msg_size != EXPECTED_SIZE) return DECODE_INVALID;` |
| 158 | +2. Validate CRC/checksum: `if (calculated_crc != expected_crc) return DECODE_CHK_ERR;` |
| 159 | +3. Extract sensor ID and type |
| 160 | +4. Decode fields with proper scaling/units |
| 161 | +5. Set validity flags for each field |
| 162 | +6. Return `DecodeStatus` |
| 163 | + |
| 164 | +## Platform-Specific Notes |
| 165 | + |
| 166 | +### Supported Platforms |
| 167 | +- **ESP32** (primary target) - full feature support |
| 168 | +- **ESP8266** - limited RAM, use carefully with multiple sensors |
| 169 | +- **RP2040** - limited testing, basic features supported |
| 170 | + |
| 171 | +### Board Configurations |
| 172 | +Predefined board configs in `WeatherSensorCfg.h`: |
| 173 | +- `LORAWAN_NODE` - Custom board based on DFRobot FireBeetle ESP32 |
| 174 | +- `DFROBOT_COVER_LORA` - DFRobot FireBeetle ESP32 with FireBeetle Cover LoRa Radio |
| 175 | +- `TTGO_LORA32` - TTGO ESP32 with integrated SX1276 |
| 176 | +- `ADAFRUIT_FEATHER_ESP32S2` - Adafruit Feather with RFM95W |
| 177 | +- `ARDUINO_DFROBOT_FIREBEETLE_ESP32` - DFRobot FireBeetle ESP32 |
| 178 | +- `ESP32_LORA_V2` - Heltec ESP32 LoRa V2 |
| 179 | +- `M5CORE2_MODULE_LORA868` - M5Stack Core2 with LoRa module |
| 180 | + |
| 181 | +### Pin Configuration |
| 182 | +Define pins in `WeatherSensorCfg.h`: |
| 183 | +```cpp |
| 184 | +#define PIN_RECEIVER_CS 27 // SPI chip select |
| 185 | +#define PIN_RECEIVER_IRQ 21 // CC1101: GDO0 / SX127x: DIO0 |
| 186 | +#define PIN_RECEIVER_GPIO 33 // CC1101: GDO2 / SX127x: DIO1 |
| 187 | +#define PIN_RECEIVER_RST 32 // Reset pin (SX127x) or RADIOLIB_NC (CC1101) |
| 188 | +``` |
| 189 | +
|
| 190 | +## Testing |
| 191 | +
|
| 192 | +### Framework |
| 193 | +- **CppUTest** for unit tests (desktop) |
| 194 | +- **arduino-ci** for Arduino library validation |
| 195 | +
|
| 196 | +### Test Structure |
| 197 | +```cpp |
| 198 | +#include "CppUTest/TestHarness.h" |
| 199 | +TEST_GROUP(TestGroupName) { |
| 200 | + void setup() { /* Initialize */ } |
| 201 | + void teardown() { /* Cleanup */ } |
| 202 | +}; |
| 203 | +
|
| 204 | +TEST(TestGroupName, TestName) { |
| 205 | + // Arrange |
| 206 | + // Act |
| 207 | + // Assert |
| 208 | + DOUBLES_EQUAL(expected, actual, tolerance); |
| 209 | +} |
| 210 | +``` |
| 211 | + |
| 212 | +### Running Tests |
| 213 | +```bash |
| 214 | +# Run CppUTest |
| 215 | +cd test |
| 216 | +make |
| 217 | + |
| 218 | +# Run Arduino CI |
| 219 | +# Automated via GitHub Actions |
| 220 | +``` |
| 221 | + |
| 222 | +## Dependencies |
| 223 | + |
| 224 | +### Core Dependencies |
| 225 | +- **RadioLib** (7.5.0) - RF transceiver abstraction layer |
| 226 | +- **ArduinoJson** (7.4.2) - JSON parsing for configuration |
| 227 | +- **Preferences** (2.2.2) - Flash storage API (ESP32/ESP8266) |
| 228 | + |
| 229 | +### Optional Dependencies |
| 230 | +- **MQTT** (2.5.2) - MQTT client for IoT integrations |
| 231 | +- **WiFiManager** (2.0.17) - WiFi credential management |
| 232 | +- **ESP_DoubleResetDetector** (1.3.2) - Factory reset via double-reset |
| 233 | +- **ESPAsyncWebServer** (3.9.4) - Web interface for configuration |
| 234 | +- **Adafruit_SSD1306** (2.5.16) - OLED display support |
| 235 | +- **RTClib** (2.1.4) - Real-time clock support |
| 236 | + |
| 237 | +## Common Tasks |
| 238 | + |
| 239 | +### Adding a New Sensor Decoder |
| 240 | +1. Add sensor type constant in `WeatherSensor.h` (e.g., `#define SENSOR_TYPE_NEW 0xNN`) |
| 241 | +2. Add decoder function in `WeatherSensorDecoders.cpp`: |
| 242 | + ```cpp |
| 243 | + DecodeStatus decodeBresserNewPayload(const uint8_t *msg, uint8_t msgSize) { |
| 244 | + // Validate length and CRC |
| 245 | + // Extract sensor ID and type |
| 246 | + // Decode fields with proper units |
| 247 | + // Set validity flags |
| 248 | + return DECODE_OK; |
| 249 | + } |
| 250 | + ``` |
| 251 | +3. Add decoder to chain in `WeatherSensor::decodeMessage()` |
| 252 | +4. Add conditional compilation guard: `#ifdef BRESSER_NEW` |
| 253 | +5. Document protocol details in comments |
| 254 | +
|
| 255 | +### Adding a New Board Configuration |
| 256 | +1. Add board definition to `WeatherSensorCfg.h`: |
| 257 | + ```cpp |
| 258 | + #elif defined(MY_BOARD) |
| 259 | + #define PIN_RECEIVER_CS XX |
| 260 | + #define PIN_RECEIVER_IRQ XX |
| 261 | + #define PIN_RECEIVER_GPIO XX |
| 262 | + #define PIN_RECEIVER_RST XX |
| 263 | + ``` |
| 264 | +2. Document pin connections |
| 265 | +3. Test RF reception and decoding |
| 266 | + |
| 267 | +### Adding Support for a New RF Transceiver |
| 268 | +1. Add transceiver type macro: `#define USE_NEW_RADIO` |
| 269 | +2. Add RadioLib module initialization in `WeatherSensor::begin()` |
| 270 | +3. Configure modulation parameters (FSK, frequency, bandwidth, etc.) |
| 271 | +4. Test message reception with known sensors |
| 272 | + |
| 273 | +## Best Practices |
| 274 | + |
| 275 | +### Memory Management |
| 276 | +- ESP8266 has limited RAM (~40KB usable) - minimize heap allocations |
| 277 | +- Use `std::vector.reserve()` if max sensor count is known |
| 278 | +- Prefer stack allocation for temporary buffers |
| 279 | +- Use unions for mutually exclusive sensor data types |
| 280 | + |
| 281 | +### RF Reception |
| 282 | +- Set appropriate RX timeout based on sensor transmit intervals (typically 30-60 seconds) |
| 283 | +- Handle incomplete 6-in-1 messages (alternating temp/humidity and rain/wind) |
| 284 | +- Clear slots before each RX cycle to prevent stale data |
| 285 | +- Check `startup` flag to prevent false rain/lightning accumulation |
| 286 | + |
| 287 | +### Sensor ID Filtering |
| 288 | +- Support both include and exclude lists |
| 289 | +- Use `rxFlags.DATA_COMPLETE` cautiously - some sensors never provide complete data |
| 290 | + |
| 291 | +### Debugging |
| 292 | +- Use `CORE_DEBUG_LEVEL` (ESP32) or `WeatherSensorCfg.h` defines (ESP8266) |
| 293 | +- Add debug output with `log_d()`, `log_i()`, `log_v()` macros |
| 294 | +- Use `DEBUG_OUTPUT.md` for debug level documentation |
| 295 | + |
| 296 | +### Version Management |
| 297 | +- Follow semantic versioning (MAJOR.MINOR.PATCH) |
| 298 | +- Update `library.properties` version field |
| 299 | +- Update `package.json` version field |
| 300 | +- Document changes in file history blocks |
| 301 | +- Update `CHANGELOG.md` (if present) |
| 302 | + |
| 303 | +## Examples Organization |
| 304 | + |
| 305 | +Examples demonstrate progressive complexity: |
| 306 | +1. **Basic** - Simple message reception and printing |
| 307 | +2. **Waiting/Callback** - Advanced reception strategies |
| 308 | +3. **Options** - Configuration customization |
| 309 | +4. **OLED** - Display integration |
| 310 | +5. **MQTT** - IoT platform integration |
| 311 | +6. **MQTTCustom** - Advanced MQTT with local library copy (for development) |
| 312 | +7. **Domoticz/M5Core2/CanvasGauges/SDCard** - Specific use cases |
| 313 | + |
| 314 | +## Integration Guidelines |
| 315 | + |
| 316 | +### MQTT Integration |
| 317 | +- Publish sensor data as JSON to topic: `<base_topic>/data` |
| 318 | +- Support MQTT auto-discovery (Home Assistant format) |
| 319 | +- Include sensor ID, type, and all available measurements |
| 320 | +- Handle TLS/SSL for secure connections |
| 321 | + |
| 322 | +### Home Assistant Integration |
| 323 | +- Use MQTT auto-discovery protocol |
| 324 | +- Publish discovery configs to: `homeassistant/<component>/<object_id>/config` |
| 325 | +- Set appropriate device classes (temperature, humidity, etc.) |
| 326 | +- Include unique IDs based on sensor ID |
| 327 | + |
| 328 | +## Security Considerations |
| 329 | +- Never commit WiFi credentials or MQTT passwords |
| 330 | +- Use `secrets.h` (gitignored) for sensitive data |
| 331 | +- Define `SECRETS` macro when using separate secrets file |
| 332 | +- Support secure WiFi (WPA2) and secure MQTT (TLS/SSL) |
| 333 | + |
| 334 | +## References & Credits |
| 335 | + |
| 336 | +### Original Work |
| 337 | +- **Bresser5in1-CC1101** by Sean Siford - Initial CC1101 implementation |
| 338 | +- **RadioLib** by Jan Gromeš - RF transceiver library |
| 339 | +- **rtl_433** by Benjamin Larsson - Protocol specifications and decoders |
| 340 | + |
| 341 | +### Protocol Documentation |
| 342 | +- [rtl_433 bresser_5in1.c](https://github.com/merbanan/rtl_433/blob/master/src/devices/bresser_5in1.c) |
| 343 | +- [rtl_433 bresser_6in1.c](https://github.com/merbanan/rtl_433/blob/master/src/devices/bresser_6in1.c) |
| 344 | +- [rtl_433 bresser_7in1.c](https://github.com/merbanan/rtl_433/blob/master/src/devices/bresser_7in1.c) |
| 345 | + |
| 346 | +### Project Resources |
| 347 | +- **Repository**: https://github.com/matthias-bs/BresserWeatherSensorReceiver |
| 348 | +- **Wiki**: https://github.com/matthias-bs/BresserWeatherSensorReceiver/wiki |
| 349 | +- **Issues**: https://github.com/matthias-bs/BresserWeatherSensorReceiver/issues |
| 350 | +- **Discussions**: Use GitHub Issues for questions and feature requests |
| 351 | + |
| 352 | +## License |
| 353 | +This project is licensed under the MIT License. All contributions must maintain the MIT license header in source files. |
0 commit comments