BresserWeatherSensorLW is a LoRaWAN-enabled weather sensor receiver for ESP32 and RP2040 microcontrollers. It receives data from Bresser 868 MHz weather sensors via a radio transceiver (SX1262/SX1276/LR1121) and forwards it to a LoRaWAN network such as The Things Network, ChirpStack, or Helium IoT.
Key Characteristics:
- Arduino sketch (
.inofile) with C++ support files - Dual-purpose radio: FSK mode for sensor reception, LoRaWAN for network communication
- Supports multiple hardware platforms: ESP32, ESP32-S2, ESP32-S3, RP2040
- Implements power-efficient deep sleep with RTC support
- Modular architecture separating network layer from application layer
-
BresserWeatherSensorLW.ino - Main sketch file
- Setup and loop functions
- LoRaWAN session management
- Deep sleep handling
- Main coordinator between components
-
AppLayer (src/AppLayer.h/cpp) - Application layer abstraction
- Sensor data collection and encoding
- Payload generation in stages
- Command/status message handling
- Separation from LoRaWAN network layer
-
Payload Modules (src/Payload.h/cpp)* - Specialized payload handlers
PayloadBresser: Weather sensor data encodingPayloadBLE: Bluetooth sensor integrationPayloadAnalog: ADC input handlingPayloadDigital: Digital I/O handlingPayloadOneWire: Temperature sensor support
-
SystemContext (src/SystemContext.h/cpp) - System state management
- Hardware-specific initialization
- RTC (Real-Time Clock) management
- Sleep interval handling
- Battery voltage monitoring
- Power-saving mode decisions
-
Configuration Files
config.h: RadioLib/LoRaWAN radio configuration and pin mappingsBresserWeatherSensorLWCfg.h: Feature flags, timing, voltage thresholdssecrets.h: LoRaWAN credentials (template with dummy values)WeatherSensorCfg.h: Sensor receiver configuration (from BresserWeatherSensorReceiver library)
-
Command Interface (BresserWeatherSensorLWCmd.h/cpp)
- LoRaWAN downlink command decoding
- Status uplink encoding
- Remote configuration support
- RadioLib (v7.5.0+): LoRaWAN communication
- BresserWeatherSensorReceiver (v0.38.2+): 868 MHz sensor data reception
- LoRa Serialization: Efficient payload encoding
- ArduinoJson (v7.4.2): Configuration file parsing
- NimBLE-Arduino (optional): BLE sensor support
- OneWireNg (optional): 1-Wire temperature sensors
- Platform: Arduino IDE, Arduino CLI, or PlatformIO
- Supported Boards:
- ESP32 variants (Feather, FireBeetle, Heltec, TTGO, etc.)
- ESP32-S2/S3 (PowerFeather, XIAO)
- RP2040 (Adafruit Feather)
- Board Manager URLs:
- ESP32:
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json - RP2040:
https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
- ESP32:
The project uses GitHub Actions workflows:
- CI.yml: Builds for multiple board variants
- arduino-lint.yml: Arduino library/sketch linting
- doxygen.yml: API documentation generation
- spell-check.yml: Documentation spell checking
Build is triggered on push/PR to main branch or via workflow dispatch.
BresserWeatherSensorLW/
├── BresserWeatherSensorLW.ino # Main Arduino sketch
├── config.h # Radio/LoRaWAN configuration
├── secrets.h # LoRaWAN credentials (template)
├── BresserWeatherSensorLWCfg.h # User configuration
├── BresserWeatherSensorLWCmd.h/cpp # Command interface
├── src/ # Application layer
│ ├── AppLayer.h/cpp # Main application layer
│ ├── Payload*.h/cpp # Payload encoders
│ ├── SystemContext.h/cpp # System state management
│ ├── LoadSecrets.h/cpp # Credential loading
│ ├── LoadNodeCfg.h/cpp # Configuration loading
│ ├── adc/ # ADC utilities
│ ├── BleSensors/ # BLE sensor code
│ ├── DistanceSensors/ # Distance sensor support
│ └── rp2040/ # RP2040-specific code
├── data/ # LittleFS data files
│ ├── secrets.json # Optional: credentials
│ └── node_config.json # Optional: deployment config
├── scripts/ # Support scripts
│ └── bresserweathersensorlw-codec/ # Payload formatters
└── extras/ # Examples and tests
-
File Headers
- Use standardized header with file description
- Include MIT license notice
- Maintain detailed history section
- Add creation date and author
-
Comments
- Doxygen-style comments for functions/classes
/*! ... */for multi-line documentation//!for single-line documentation//for inline comments
-
Naming Conventions
- Classes: PascalCase (e.g.,
AppLayer,PayloadBresser) - Functions: camelCase (e.g.,
getPayloadStage1,genPayload) - Constants: UPPER_SNAKE_CASE (e.g.,
MAX_UPLINK_SIZE,PIN_LORA_NSS) - Member variables: camelCase (e.g.,
weatherSensor,appPrefs) - Defines: UPPER_SNAKE_CASE with descriptive prefixes
- Classes: PascalCase (e.g.,
-
Preprocessor Usage
- Use
#if defined()for platform detection - Group platform-specific code with clear markers
- Provide pragma messages for configuration guidance
- Use include guards:
#if !defined(_FILENAME_H)
- Use
Handle platform differences using preprocessor directives:
#if defined(ARDUINO_ARCH_ESP32)
// ESP32-specific code
#elif defined(ARDUINO_ARCH_RP2040)
// RP2040-specific code
#endifCommon board defines:
ARDUINO_FEATHER_ESP32ARDUINO_DFROBOT_FIREBEETLE_ESP32ARDUINO_HELTEC_WIFI_LORA_32_V3ARDUINO_TTGO_LORA32_*ARDUINO_ADAFRUIT_FEATHER_ESP32S2ARDUINO_ADAFRUIT_FEATHER_RP2040
Use a layered configuration approach:
-
Compile-time Configuration (header files)
- Feature enable/disable flags
- Pin definitions per board
- Default values
-
Runtime Configuration (JSON files on LittleFS)
- LoRaWAN credentials (
secrets.json) - Deployment-specific settings (
node_config.json)
- LoRaWAN credentials (
-
Persistent Storage (Preferences/NVS)
- User-modifiable settings
- Calibration values
- BLE device addresses
Example pattern:
#if defined(MY_BOARD)
#define PIN_LORA_NSS 5
#define PIN_LORA_RST 14
// ... more pins
#endifThe AppLayer class provides the main interface between LoRaWAN and application logic. It uses multiple inheritance to compose functionality from specialized payload handlers:
class AppLayer : public PayloadBresser, PayloadAnalog, PayloadDigitalKey methods:
begin(): Initialize sensors and preferencesgetPayloadStage1(): First payload encoding pass (sensor data)getPayloadStage2(): Second payload encoding pass (additional data)decodeDownlink(): Process incoming LoRaWAN commandsgetAppStatusUplinkInterval(): Return status update interval
This composition pattern allows different sensor types to be easily enabled/disabled without changing core logic.
Use LoraEncoder from LoRa-Serialization library for efficient encoding:
void encodeMyData(LoraEncoder &encoder) {
encoder.writeTemperature(temperature);
encoder.writeHumidity(humidity);
encoder.writeUint16(pressure);
}Signal invalid data using defined constants:
- Temperature:
INV_TEMP(32767) - Humidity:
INV_UINT8(255) - Voltage:
INV_UINT16(65535) - etc.
For battery-powered operation:
- Check battery voltage with
getBatteryVoltage() - Compare against thresholds:
VOLTAGE_CRITICAL,VOLTAGE_ECO_ENTER - Adjust sleep time and features based on power state
- Use deep sleep between transmissions
- Use
SystemContextfor time tracking - Support both internal RTC and external RTC chips
- Handle time synchronization via LoRaWAN
- Implement time-based algorithms (rain gauge, lightning stats)
Use Arduino logging macros (ESP32) or custom macros (RP2040):
log_d(): Debug messageslog_i(): Informational messageslog_w(): Warningslog_e(): Errors
Enable via Arduino IDE: Tools → Core Debug Level
- LoRaWAN Version: 1.1.0 (default) or 1.0.4
- Region: Configurable (EU868, US915, etc.)
- Join Method: OTAA (Over-The-Air Activation)
- Credentials: JoinEUI, DevEUI, AppKey, NwkKey (v1.1)
Multiple message types on different ports:
- Port 1: Sensor data (default)
- Port 2: LoRaWAN node status
- Port 3: Application/sensor status
- Port 10+: Command responses
Remote configuration via LoRaWAN downlink:
- Set payload configuration
- Configure BLE sensors
- Adjust sensor reception parameters
- Request status information
- Trigger sensor scanning
Implemented in BresserWeatherSensorLWCmd.h/cpp
-
Standalone Sensor Reception
- Test BresserWeatherSensorReceiver first
- Use examples/BresserWeatherSensorBasic
- Verify sensor data reception before LoRaWAN
-
LoRaWAN Join
- Verify credentials are correct
- Check join success in serial output
- Confirm on network server
-
Payload Validation
- Use payload formatters in
scripts/bresserweathersensorlw-codec/ - Test with real sensor data
- Verify decoded values match transmitted
- Use payload formatters in
Enable via BresserWeatherSensorLWCfg.h or Arduino IDE debug level:
- View sensor reception events
- Monitor LoRaWAN join/uplink/downlink
- Track sleep/wake cycles
- Observe battery voltage readings
See Debug_Output.md for details.
- Find board define (compile empty sketch with verbose output)
- Add section in
BresserWeatherSensorLWCfg.h - Define pins and board-specific settings
- Add section in
config.hfor radio pins - If needed, add to
WeatherSensorCfg.h(sensor receiver pins) - Test and document
- Create payload encoder in
src/Payload<SensorType>.h/cpp - Add payload configuration options
- Update
AppLayerto call encoder - Add command support if needed
- Update payload formatters for decoding
- Document in README
- Review
APP_PAYLOAD_CFG_*defines inBresserWeatherSensorLWCfg.h - Modify
appPayloadCfgDefarray inAppLayer.h - Use config helper in
extras/confighelper/to visualize - Adjust payload formatters accordingly
- Create JSON file in
data/directory - Upload to LittleFS using appropriate tool:
- ESP32: ESP32 Sketch Data Upload or esp-idf tools
- RP2040: Pico-W-Go or picotool
- Enable file loading in code:
loadSecrets()for credentialsloadNodeCfg()for deployment config
-
Preserve Existing Architecture
- Don't merge application and network layers
- Maintain separation between sensor types
- Keep configuration modular
-
Platform Compatibility
- Always consider ESP32 and RP2040 differences
- Test platform-specific code paths
- Use appropriate includes (e.g.,
Arduino.hvs ESP32-specific)
-
Memory Constraints
- Embedded systems have limited RAM
- Use stack allocation where possible
- Be mindful of array sizes and buffers
MAX_UPLINK_SIZElimits payload
-
Power Efficiency
- Minimize wake time
- Use appropriate sleep modes
- Consider battery life impact
-
LoRaWAN Compliance
- Respect duty cycle regulations
- Don't exceed data rate limits
- Follow Regional Parameters
-
Backward Compatibility
- Maintain API compatibility when possible
- Document breaking changes clearly
- Consider migration path for users
-
Prerequisites for Contributors
- Not the first Arduino sketch to try - test with simpler sketches first
- Test BresserWeatherSensorReceiver standalone before integration
- Understand LoRaWAN fundamentals (see The Things Network documentation)
- Use RadioLib v7.5.0+ and arduino-esp32 v3.X.Y
- Read RadioLib LoRaWAN starter guide
-
Code Generation Guidelines
- Always include MIT license header with copyright notice
- Maintain detailed history section in file headers
- Use Doxygen-style comments for public APIs
- Follow existing naming conventions strictly
- Add platform-specific guards for new features
- RadioLib Documentation
- BresserWeatherSensorReceiver
- The Things Network Docs
- LoRaWAN Specification
- Project README
- API Documentation
This project is licensed under the MIT License. All generated code should include appropriate MIT license headers and copyright notices.