diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 2569c5fb..4afcd8e3 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -20,6 +20,7 @@ jobs: #- esp32:esp32:ttgo-lora32:Revision=TTGO_LoRa32_V2 - esp32:esp32:ttgo-lora32:Revision=TTGO_LoRa32_v21new - esp32:esp32:heltec_wireless_stick:PSRAM=disabled + - esp32:esp32:heltec_wifi_lora_32_V2 - esp32:esp32:adafruit_feather_esp32s2 - esp32:esp32:featheresp32 - esp8266:esp8266:generic:dbg=Disabled @@ -86,10 +87,12 @@ jobs: run: | ps -p "$$" - arduino-cli lib install RadioLib@6.0.0 + arduino-cli lib install RadioLib@6.1.0 arduino-cli lib install "LoRa Serialization"@3.1.0 arduino-cli lib install MQTT@2.5.1 arduino-cli lib install ArduinoJson@6.21.2 + arduino-cli lib install WiFiManager@2.0.16-rc.2 + arduino-cli lib install ESP_DoubleResetDetector@1.3.2 - name: Install platform if: ${{ env.run-build == 'true' }} diff --git a/README.md b/README.md index 53d4c3ee..02a70094 100644 --- a/README.md +++ b/README.md @@ -16,22 +16,35 @@ To allow automatic handling of all Bresser weather station variants, the decoder | Model | Type | Decoder Function | | ------------- | ---- | ------------------------------- | -| 7002510..12 | Weather Station | decodeBresser**5In1**Payload() | +| 7002510..12, 9602510 | Weather Station | decodeBresser**5In1**Payload() | | 7902510..12 | Weather Station (Base) | decodeBresser**5In1**Payload() | | *7002531* | *3-in-1 Professional Wind Gauge / Anemometer* | *decodeBresser**6In1**Payload()* **1)** | | 7002585 | Weather Station | decodeBresser**6In1**Payload() | -| 9602510 | Weather Sensor | ? | | 7009999 | Thermo-/Hygrometer Sensor | decodeBresser**6in1**Payload() | | 7009972 | Soil Moisture/Temperature Sensor | decodeBresser**6In1**Payload() | -| 7003600000000 and WSX3001000000 | Weather Station | decodeBresser**7In1**Payload() | +| 7003600000000 and WSX3001000000 | Weather Station | decodeBresser**7In1**Payload() **2)** | +| 7803200 | Weather Sensor | decodeBresser**7In1**Payload() | +| 7003300 | Weather Station | decodeBresser**7In1**Payload() | +| 7803300 | Weather Sensor | decodeBresser**7In1**Payload() | -**1)** negative temperatures are currently not decoded correctly, UV flag is set erroneously; see https://github.com/matthias-bs/BresserWeatherSensorReceiver/issues/42 +Some guesswork: + +| Numbering Scheme | Type | +| ---------------- | ---- | +| 700[25\|32\|33]* | Weather Station, Base + Sensor | +| 780[25\|32\|33]* | Weather Station Sensor (Replacement) | +| 790* | Weather Station Base (Replacement) | +| 700[99]* | Accessory Sensor | + +**1)** Manual configuration required, UV flag is set erroneously; see https://github.com/matthias-bs/BresserWeatherSensorReceiver/issues/42 + +**2)** The part number is specific to the actual variant. ## Configuration ### Configuration by selecting a supported Board in the Arduino IDE -By selecting a Board and a Board Revision in the Arduino IDE, a define is passed to the preprocessor/compiler. For the boards in the table below, the default configuration is assumed based on this define. I.e. you could could use an Adafruit Feather ESP32-S2 with a CC1101 connected to the pins of you choice of course, but the code assumes you are using it with a LoRa Radio Featherwing with the wiring given below. +By selecting a Board and a Board Revision in the Arduino IDE, a define is passed to the preprocessor/compiler. For the boards in the table below, the default configuration is assumed based on this define. I.e. you could could use an Adafruit Feather ESP32-S2 with a CC1101 connected to the pins of your choice of course, but the code assumes you are using it with a LoRa Radio Featherwing with the wiring given below. If you are not using the Arduino IDE, you can use the defines in the table below with your specific tool chain to get the same result. @@ -42,7 +55,8 @@ If this is not what you need, you have to switch to **Manual Configuration** | [LILYGO®TTGO-LORA32 V1](https://github.com/Xinyuan-LilyGo/TTGO-LoRa-Series) | "TTGO LoRa32-OLED" | "TTGO LoRa32 V1 (No TFCard)" | ARDUINO_TTGO_LORA32_V1 | SX1276 (HPD13A) | - | | [LILYGO®TTGO-LORA32 V2](https://github.com/LilyGO/TTGO-LORA32) | "TTGO LoRa32-OLED" | "TTGO LoRa32 V2" | ARDUINO_TTGO_LoRa32_V2 | SX1276 (HPD13A) | Wire DIO1 to GPIO33 | | [LILYGO®TTGO-LORA32 V2.1](http://www.lilygo.cn/prod_view.aspx?TypeId=50060&Id=1271&FId=t3:50060:3) | "TTGO LoRa32-OLED" | "TTGO LoRa32 V2.1 (1.6.1)" | ARDUINO_TTGO_LoRa32_v21new | SX1276 (HPD13A) | - | - | [Heltec Wireless Stick](https://heltec.org/project/wireless-stick/) | "Heltec Wireless Stick" | n.a. | ARDUINO_heltec_wireless_stick | SX1276 | - | + | [Heltec Wireless Stick](https://heltec.org/project/wireless-stick/) | "Heltec Wireless Stick" | n.a. | ARDUINO_heltec_wireless_stick | SX1276 | - | + | [Heltec WiFi LoRa 32 V2](https://heltec.org/project/wifi-lora-32/) | "Heltec WiFi LoRa 32(V2)" | n.a. | ARDUINO_heltec_wifi_lora_32_V2 | SX1276 | - | | [Adafruit Feather ESP32S2 with Adafruit LoRa Radio FeatherWing](https://github.com/matthias-bs/BresserWeatherSensorReceiver#adafruit-feather-esp32s2-with-adafruit-lora-radio-featherwing) | "Adafruit Feather ESP32-S2" | n.a. | ARDUINO_ADAFRUIT_FEATHER_ESP32S2 | SX1276 (RFM95W) | Wiring on the Featherwing:
E to IRQ
D to CS
C to RST
A to DI01 | | [Adafruit Feather ESP32 or ThingPulse ePulse Feather with Adafruit LoRa Radio FeatherWing](https://github.com/matthias-bs/BresserWeatherSensorReceiver/blob/main/README.md#adafruit-feather-esp32-or-thingpulse-epulse-feather-with-adafruit-lora-radio-featherwing) | "Adafruit ESP32 Feather" | n.a. | ARDUINO_FEATHER_ESP32 | SX1276 (RFM95W) | Wiring on the Featherwing:
A to RST
B to DIO1
D to IRQ
E to CS | | [DFRobot FireBeetle with FireBeetle Cover LoRa Radio 868MHz](https://github.com/matthias-bs/BresserWeatherSensorReceiver/blob/main/README.md#dfrobot-firebeetle-esp32-with-firebeetle-cover-lora-radio-868mhz) | "FireBeetle-ESP32" | n.a. | ARDUINO_ESP32_DEV & **FIREBEETLE_ESP32_COVER_LORA**1 | SX1276 (LoRa1276) | Wiring on the cover:
D2 to RESET
D3 to DIO0
D4 to CS
D5 to DIO1 | @@ -143,6 +157,7 @@ $ via LWT ``` {"sensor_id":12345678,"ch":0,"battery_ok":true,"humidity":44,"wind_gust":1.2,"wind_avg":1.2,"wind_dir":150,"rain":146} ``` + **Dashboard with [IoT MQTT Panel](https://snrlab.in/iot/iot-mqtt-panel-user-guide) (Example)** IoTMQTTPanel_Bresser_5-in-1 @@ -156,6 +171,29 @@ The file [BresserWeatherSensorReceiver/examples/BresserWeatherSensorMQTTCustom/s See [examples/BresserWeatherSensorMQTTCustom/Readme.md](https://github.com/matthias-bs/BresserWeatherSensorReceiver/blob/main/examples/BresserWeatherSensorMQTTCustom/Readme.md) for details. +### [BresserWeatherSensorMQTTWiFiMgr](https://github.com/matthias-bs/BresserWeatherSensorReceiver/examples/BresserWeatherSensorMQTTWiFiMgr) + +Same core functionality as [BresserWeatherSensorMQTT](https://github.com/matthias-bs/BresserWeatherSensorReceiver/blob/main/examples/BresserWeatherSensorMQTT/BresserWeatherSensorMQTT.ino), but instead of using static WiFi- and MQTT-connection data, [WiFiManager](https://github.com/tzapu/WiFiManager) is used instead. + +**Note:** + +When using the sketch on a device for the first time, you must format the flash file system (SPIFFS) first, otherwise the configuration cannot be saved. + +**Configuration:** + +* Access Point SSID: ESPWeather- +* Access Point Password: password +* Configuration URL: http://192.168.4.1/ (The browser must be connected to the access point above!) + +Please refer to the [WiFiManager](https://github.com/tzapu/WiFiManager) documentation for details! + +After a successful setup, you can perform two consecutive resets (within 10 seconds) to enable WiFiManager for changing the configuration. This is achieved by using [ESP_DoubleResetDetector](https://github.com/khoih-prog/ESP_DoubleResetDetector). + +WiFiManager Start Screen +
+WiFiManager Configuration Screen + + ### [BresserWeatherSensorDomoticz](https://github.com/matthias-bs/BresserWeatherSensorReceiver/examples/BresserWeatherSensorDomoticz) Based on [BresserWeatherSensorMQTT](https://github.com/matthias-bs/BresserWeatherSensorReceiver/examples/BresserWeatherSensorMQTT). Provides sensor data as MQTT messages via WiFi to Domoticz (https://domoticz.com/) (MQTT plugin for Domoticz required). The MQTT topics are designed for using with Domoticz virtual sensors (see https://www.domoticz.com/wiki/Managing_Devices#Temperature and https://www.domoticz.com/wiki/Managing_Devices#Weather). diff --git a/examples/BresserWeatherSensorMQTTCustom/src/WeatherSensor.cpp b/examples/BresserWeatherSensorMQTTCustom/src/WeatherSensor.cpp index 58ae6648..0d5c4577 100644 --- a/examples/BresserWeatherSensorMQTTCustom/src/WeatherSensor.cpp +++ b/examples/BresserWeatherSensorMQTTCustom/src/WeatherSensor.cpp @@ -56,6 +56,10 @@ // 20230114 Modified decodeBresser6In1Payload() to distinguish msg type based on 'flags' (msg[16]) // 20230228 Added Bresser 7 in 1 decoder by Jorge Navarro-Ortiz (jorgenavarro@ugr.es) // 20230329 Fixed issue introduced with 7 in 1 decoder +// 20230412 Added workaround for Professional Wind Gauge / Anemometer, P/N 7002531 +// 20230412 Fixed 7 in 1 decoder (valid/complete flags were not set) +// 20230613 Fixed rain value in 7 in 1 decoder +// 20230708 Added startup flag in 6-in-1 and 7-in-1 decoder; added sensor type in 7-in-1 decoder // // ToDo: // - @@ -79,6 +83,10 @@ uint32_t const sensor_ids_exc[] = SENSOR_IDS_EXC; // List of sensor IDs to be included - if empty, handle all available sensors uint32_t const sensor_ids_inc[] = SENSOR_IDS_INC; +// List of sensor IDs of the model "BRESSER 3-in-1 Professional Wind Gauge / Anemometer" +// P/N 7002531 - requiring special heandling in decodeBresser5In1Payload() +uint32_t const sensor_ids_decode3in1[] = SENSOR_IDS_DECODE3IN1; + int16_t WeatherSensor::begin(void) { // https://github.com/RFD-FHEM/RFFHEM/issues/607#issuecomment-830818445 // Freq: 868.300 MHz, Bandwidth: 203 KHz, rAmpl: 33 dB, sens: 8 dB, DataRate: 8207.32 Baud @@ -385,6 +393,22 @@ int WeatherSensor::findType(uint8_t type, uint8_t ch) return -1; } +// +// Check if sensor is in sensor_ids_decode3in1[] +// +bool WeatherSensor::is_decode3in1(uint32_t id) +{ + uint8_t n_3in1 = sizeof(sensor_ids_decode3in1)/4; + if (n_3in1 != 0) { + for (int i=0; i> 4) * 10 + (msg[21] &0x0f) * 100; if (msg[25] & 0x0f) { @@ -574,7 +599,7 @@ DecodeStatus WeatherSensor::decodeBresser5In1Payload(uint8_t *msg, uint8_t msgSi // Moisture: // // f16e 187000e34 7 ffffff0000 252 2 16 fff 004 000 [25,2, 99%, CH 7] -// DIGEST:8h8h ID?8h8h8h8h STYPE:4h STARTUP:1b CH:3d 8h 8h8h 8h8h TEMP:12h ?2b BATT:1b ?1b MOIST:8h UV?~12h ?4h CHKSUM:8h +// DIGEST:8h8h ID?8h8h8h8h :4h STARTUP:1b CH:3d 8h 8h8h 8h8h TEMP:12h ?2b BATT:1b ?1b MOIST:8h UV?~12h ?4h CHKSUM:8h // // Moisture is transmitted in the humidity field as index 1-16: 0, 7, 13, 20, 27, 33, 40, 47, 53, 60, 67, 73, 80, 87, 93, 99. // The Wind speed and direction fields decode to valid zero but we exclude them from the output. @@ -612,8 +637,8 @@ DecodeStatus WeatherSensor::decodeBresser5In1Payload(uint8_t *msg, uint8_t msgSi // // Wind and Temperature/Humidity or Rain: // -// DIGEST:8h8h ID:8h8h8h8h STYPE:4h STARTUP:1b CH:3d WSPEED:~8h~4h ~4h~8h WDIR:12h ?4h TEMP:8h.4h ?2b BATT:1b ?1b HUM:8h UV?~12h ?4h CHKSUM:8h -// DIGEST:8h8h ID:8h8h8h8h STYPE:4h STARTUP:1b CH:3d WSPEED:~8h~4h ~4h~8h WDIR:12h ?4h RAINFLAG:8h RAIN:8h8h UV:8h8h CHKSUM:8h +// DIGEST:8h8h ID:8h8h8h8h :4h STARTUP:1b CH:3d WSPEED:~8h~4h ~4h~8h WDIR:12h ?4h TEMP:8h.4h ?2b BATT:1b ?1b HUM:8h UV?~12h ?4h CHKSUM:8h +// DIGEST:8h8h ID:8h8h8h8h :4h STARTUP:1b CH:3d WSPEED:~8h~4h ~4h~8h WDIR:12h ?4h RAINFLAG:8h RAIN:8h8h UV:8h8h CHKSUM:8h // // Digest is LFSR-16 gen 0x8810 key 0x5412, excluding the add-checksum and trailer. // Checksum is 8-bit add (with carry) to 0xff. @@ -651,6 +676,7 @@ DecodeStatus WeatherSensor::decodeBresser6In1Payload(uint8_t *msg, uint8_t msgSi bool wind_ok = false; bool rain_ok = false; bool moisture_ok = false; + bool f_3in1 = false; // LFSR-16 digest, generator 0x8810 init 0x5412 int chkdgst = (msg[0] << 8) | msg[1]; @@ -678,27 +704,33 @@ DecodeStatus WeatherSensor::decodeBresser6In1Payload(uint8_t *msg, uint8_t msgSi if (status != DECODE_OK) return status; - // unused... - //int startup = (msg[6] >> 3) & 1; // s.a. #1214 - sensor[slot].sensor_id = id_tmp; sensor[slot].s_type = type_tmp; sensor[slot].chan = chan_tmp; + sensor[slot].startup = (msg[6] >> 3) & 1; // s.a. #1214 + f_3in1 = is_decode3in1(id_tmp); // temperature, humidity(, uv) - shared with rain counter temp_ok = humidity_ok = (flags == 0); if (temp_ok) { bool sign = (msg[13] >> 3) & 1; int temp_raw = (msg[12] >> 4) * 100 + (msg[12] & 0x0f) * 10 + (msg[13] >> 4); - float temp = ((sign) ? (temp_raw - 1000) : temp_raw) * 0.1f; - + float temp; + + // Workaround for 3-in-1 Professional Wind Gauge / Anemometer + if (f_3in1) { + temp = ((sign) ? -temp_raw : temp_raw) * 0.1f; + } else { + temp = ((sign) ? (temp_raw - 1000) : temp_raw) * 0.1f; + } + sensor[slot].temp_c = temp; sensor[slot].battery_ok = (msg[13] >> 1) & 1; // b[13] & 0x02 is battery_good, s.a. #1993 sensor[slot].humidity = (msg[14] >> 4) * 10 + (msg[14] & 0x0f); // apparently ff01 or 0000 if not available, ???0 if valid, inverted BCD - uv_ok = (~msg[15] & 0xff) <= 0x99 && (~msg[16] & 0xf0) <= 0x90; + uv_ok = (~msg[15] & 0xff) <= (0x99 && (~msg[16] & 0xf0) <= 0x90) && !f_3in1; if (uv_ok) { int uv_raw = ((~msg[15] & 0xf0) >> 4) * 100 + (~msg[15] & 0x0f) * 10 + ((~msg[16] & 0xf0) >> 4); sensor[slot].uv = uv_raw * 0.1f; @@ -768,8 +800,10 @@ DecodeStatus WeatherSensor::decodeBresser6In1Payload(uint8_t *msg, uint8_t msgSi sensor[slot].valid = true; - // Weather station data is split into two separate messages - sensor[slot].complete = ((sensor[slot].s_type == SENSOR_TYPE_WEATHER1) && sensor[slot].temp_ok && sensor[slot].rain_ok) || (sensor[slot].s_type != SENSOR_TYPE_WEATHER1); + // Weather station data is split into two separate messages (except for Professional Wind Gauge) + sensor[slot].complete = ((sensor[slot].s_type == SENSOR_TYPE_WEATHER1) && sensor[slot].temp_ok && sensor[slot].rain_ok) || + f_3in1 || + (sensor[slot].s_type != SENSOR_TYPE_WEATHER1); // Save rssi to sensor specific data set sensor[slot].rssi = rssi; @@ -833,8 +867,7 @@ DecodeStatus WeatherSensor::decodeBresser7In1Payload(uint8_t *msg, uint8_t msgSi int wdir = (msgw[4] >> 4) * 100 + (msgw[4] & 0x0f) * 10 + (msgw[5] >> 4); int wgst_raw = (msgw[7] >> 4) * 100 + (msgw[7] & 0x0f) * 10 + (msgw[8] >> 4); int wavg_raw = (msgw[8] & 0x0f) * 100 + (msgw[9] >> 4) * 10 + (msgw[9] & 0x0f); - //int rain_raw = (msgw[10] >> 4) * 100000 + (msgw[10] & 0x0f) * 10000 + (msgw[11] >> 4) * 1000 + (msgw[11] & 0x0f) * 100 + (msgw[12] >> 4) * 10 + (msgw[12] & 0x0f) * 1; // 6 digits - int rain_raw = (msgw[10] >> 4) * 1000 + (msgw[10] & 0x0f) * 100 + (msgw[11] >> 4) * 10 + (msgw[11] & 0x0f) * 1; // 4 digits + int rain_raw = (msgw[10] >> 4) * 100000 + (msgw[10] & 0x0f) * 10000 + (msgw[11] >> 4) * 1000 + (msgw[11] & 0x0f) * 100 + (msgw[12] >> 4) * 10 + (msgw[12] & 0x0f) * 1; // 6 digits float rain_mm = rain_raw * 0.1f; int temp_raw = (msgw[14] >> 4) * 100 + (msgw[14] & 0x0f) * 10 + (msgw[15] >> 4); float temp_c = temp_raw * 0.1f; @@ -860,6 +893,8 @@ DecodeStatus WeatherSensor::decodeBresser7In1Payload(uint8_t *msg, uint8_t msgSi sensor[slot].uv_ok = true; sensor[slot].sensor_id = id_tmp; + sensor[slot].s_type = msgw[6] >> 4; + sensor[slot].startup = (msgw[6] & 0x08) == 0x08; sensor[slot].temp_c = temp_c; sensor[slot].humidity = humidity; #ifdef WIND_DATA_FLOATINGPOINT @@ -877,6 +912,8 @@ DecodeStatus WeatherSensor::decodeBresser7In1Payload(uint8_t *msg, uint8_t msgSi sensor[slot].light_lux = light_lux; sensor[slot].uv = uv_index; sensor[slot].battery_ok = !battery_low; + sensor[slot].valid = true; + sensor[slot].complete = true; sensor[slot].rssi = rssi; /* clang-format off */ diff --git a/examples/BresserWeatherSensorMQTTCustom/src/WeatherSensor.h b/examples/BresserWeatherSensorMQTTCustom/src/WeatherSensor.h index f6a86369..f75dba49 100644 --- a/examples/BresserWeatherSensorMQTTCustom/src/WeatherSensor.h +++ b/examples/BresserWeatherSensorMQTTCustom/src/WeatherSensor.h @@ -53,6 +53,9 @@ // 20220110 Added WEATHER0_RAIN_OV/WEATHER1_RAIN_OV // 20230228 Added Bresser 7 in 1 decoder by Jorge Navarro-Ortiz (jorgenavarro@ugr.es) // 20230328 Added MSG_BUF_SIZE +// 20230330 Added changes for Adafruit Feather 32u4 LoRa Radio +// 20230412 Added workaround for Professional Wind Gauge / Anemometer, P/N 7002531 +// 20230708 Added SENSOR_TYPE_WEATHER_7IN1 and startup flag // // ToDo: // - @@ -63,16 +66,19 @@ #define WeatherSensor_h #include -#include +#if defined(ESP32) || defined(ESP8266) + #include +#endif #include // Sensor Types -// 0 - Weather Station 5-in-1; PN 7002510..12/7902510..12 -// 1 - Weather Station 6-in-1; PN 7002585 -// 2 - Thermo-/Hygro-Sensor 6-in-1; PN 7009999 -// 4 - Soil Moisture Sensor 6-in-1; PN 7009972 -// 9 - Professional Rain Gauge (5-in-1 decoder) +// 0 - Weather Station 5-in-1; PN 7002510..12/7902510..12 +// 1 - Weather Station 6-in-1; PN 7002585 +// 2 - Thermo-/Hygro-Sensor 6-in-1; PN 7009999 +// 4 - Soil Moisture Sensor 6-in-1; PN 7009972 +// 9 - Professional Rain Gauge (5-in-1 decoder) +// 11 - Weather Sensor 7-in-1 7-in-1; PN 7003300 // ? - Air Quality Sensor // ? - Water Leakage Sensor // ? - Pool Thermometer @@ -82,6 +88,7 @@ #define SENSOR_TYPE_THERMO_HYGRO 2 // Thermo-/Hygro-Sensor #define SENSOR_TYPE_SOIL 4 // Soil Temperature and Moisture (from 6-in-1 decoder) #define SENSOR_TYPE_RAIN 9 // Professional Rain Gauge (from 5-in-1 decoder) +#define SENSOR_TYPE_WEATHER_7IN1 11 // Weather Sensor 7-in-1 // Sensor specific rain gauge overflow threshold (mm) @@ -103,6 +110,7 @@ typedef enum DecodeStatus { } DecodeStatus; +#if defined(ESP32) || defined(ESP8266) /*! * \struct SensorMap * @@ -112,6 +120,7 @@ typedef struct SensorMap { uint32_t id; //!< ID if sensor (as transmitted in radio message) std::string name; //!< Name of sensor (e.g. for MQTT topic) } SensorMap; +#endif /*! @@ -175,6 +184,7 @@ class WeatherSensor { uint32_t sensor_id; //!< sensor ID (5-in-1: 1 byte / 6-in-1: 4 bytes) uint8_t s_type; //!< sensor type (only 6-in1) uint8_t chan; //!< channel (only 6-in-1) + bool startup = false; //!< startup after reset / battery change bool valid; //!< data valid (but not necessarily complete) bool complete; //!< data is split into two separate messages is complete (only 6-in-1 WS) bool temp_ok = false; //!< temperature o.k. (only 6-in-1) @@ -266,6 +276,16 @@ class WeatherSensor { */ int findType(uint8_t type, uint8_t channel = 0xFF); + /*! + * Check if sensor ID is in sensor_ids_decode3in1[] + * + * \param id sensor ID + * + * \returns true if sensor is in sensor_ids_decode3in1[], + * false otherwise + */ + bool is_decode3in1(uint32_t id); + private: struct Sensor *pData; //!< pointer to slot in sensor data array diff --git a/examples/BresserWeatherSensorMQTTCustom/src/WeatherSensorCfg.h b/examples/BresserWeatherSensorMQTTCustom/src/WeatherSensorCfg.h index c3b47bb8..d32a8c40 100644 --- a/examples/BresserWeatherSensorMQTTCustom/src/WeatherSensorCfg.h +++ b/examples/BresserWeatherSensorMQTTCustom/src/WeatherSensorCfg.h @@ -42,6 +42,7 @@ // 20230330 Added pin definitions and changes for Adafruit Feather 32u4 (AVR) RFM95 LoRa Radio // 20230412 Added workaround for Professional Wind Gauge / Anemometer, P/N 7002531 // 20230420 Added pin definitions for DFRobot FireBeetle ESP32 with FireBeetle Cover LoRa +// 20230607 Added pin definitions for Heltec WiFi LoRa 32(V2) // // ToDo: // - @@ -81,6 +82,10 @@ // in the Arduino IDE: //#define ARDUINO_heltec_wireless_stick +// This define is set by selecting "Board: Heltec WiFi LoRa 32(V2)" +// in the Adruino IDE: +//#define ARDUINO_heltec_wifi_lora_32_V2 + // Adafruit Feather ESP32S2 with RFM95W "FeatherWing" ADA3232 // https://github.com/espressif/arduino-esp32/blob/master/variants/adafruit_feather_esp32s2/pins_arduino.h // @@ -116,6 +121,10 @@ #pragma message("ARDUINO_heltec_wireless_stick defined; using on-board transceiver") #define USE_SX1276 +#elif defined(ARDUINO_heltec_wifi_lora_32_V2) + #pragma message("ARDUINO_heltec_wifi_lora_32_V2 defined; using on-board transceiver") + #define USE_SX1276 + #elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32S2) #pragma message("ARDUINO_ADAFRUIT_FEATHER_ESP32S2 defined; assuming RFM95W FeatherWing will be used") #define USE_SX1276 @@ -125,15 +134,27 @@ #define USE_SX1276 #pragma message("Required wiring: A to RST, B to DIO1, D to DIO0, E to CS") -#elif defined(ARDUINO_ESP32_DEV) - #pragma message("Generic ESP32; assuming this is the LoRaWAN_Node board (DFRobot Firebeetle32 + Adafruit RFM95W LoRa Radio)") - #define LORAWAN_NODE - #define USE_SX1276 - #elif defined(ARDUINO_AVR_FEATHER32U4) - #pragma message("ARDUINO_AVR_FEATHER32U4 defined; assuming this is the Arduino Feather 32u4 RFM95 LoRa Radio") + #pragma message("ARDUINO_AVR_FEATHER32U4 defined; assuming this is the Adafruit Feather 32u4 RFM95 LoRa Radio") #define USE_SX1276 - + +#elif defined(ARDUINO_ESP32_DEV) + //#define LORAWAN_NODE + #define FIREBEETLE_ESP32_COVER_LORA + + #if !defined(LORAWAN_NODE) && !defined(FIREBEETLE_ESP32_COVER_LORA) + #pragma message("ARDUINO_ESP32_DEV defined; select either LORAWAN_NODE or FIREBEETLE_ESP32_COVER_LORA manually!") + + #elif defined(LORAWAN_NODE) + #pragma message("LORAWAN_NODE defined; assuming this is the LoRaWAN_Node board (DFRobot Firebeetle32 + Adafruit RFM95W LoRa Radio)") + #define USE_SX1276 + + #elif defined(FIREBEETLE_ESP32_COVER_LORA) + #define USE_SX1276 + #pragma message("FIREBEETLE_ESP32_COVER_LORA defined; assuming this is a FireBeetle ESP32 with FireBeetle Cover LoRa") + #pragma message("Required wiring: D2 to RESET, D3 to DIO0, D4 to CS, D5 to DIO1") + + #endif #endif @@ -219,6 +240,7 @@ #endif + // Replacement for // https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-log.h // on Arduino AVR: @@ -315,6 +337,18 @@ // RFM95W/SX127x - GPIOxx / CC1101 - RADIOLIB_NC #define PIN_RECEIVER_RST 12 +#elif defined(FIREBEETLE_ESP32_COVER_LORA) + #define PIN_RECEIVER_CS 27 // D4 + + // CC1101: GDO0 / RFM95W/SX127x: G0 + #define PIN_RECEIVER_IRQ 26 // D3 + + // CC1101: GDO2 / RFM95W/SX127x: G1 + #define PIN_RECEIVER_GPIO 9 // D5 + + // RFM95W/SX127x - GPIOxx / CC1101 - RADIOLIB_NC + #define PIN_RECEIVER_RST 25 // D2 + #elif defined(ARDUINO_TTGO_LoRa32_V1) || defined(ARDUINO_TTGO_LoRa32_V2) // Use pinning for LILIGO TTGO LoRa32-OLED #define PIN_RECEIVER_CS LORA_CS @@ -343,8 +377,8 @@ // RFM95W/SX127x - GPIOxx / CC1101 - RADIOLIB_NC #define PIN_RECEIVER_RST LORA_RST -#elif defined(ARDUINO_heltec_wireless_stick) - // Use pinning for Heltec Wireless Stick +#elif defined(ARDUINO_heltec_wireless_stick) || defined(ARDUINO_heltec_wifi_lora_32_V2) + // Use pinning for Heltec Wireless Stick or WiFi LoRa32 V2, respectively #define PIN_RECEIVER_CS SS // CC1101: GDO0 / RFM95W/SX127x: G0 @@ -394,7 +428,7 @@ // RFM95W/SX127x - GPIOxx / CC1101 - RADIOLIB_NC #define PIN_RECEIVER_RST 32 - + #elif defined(ESP8266) // Generic pinning for ESP8266 development boards (e.g. LOLIN/WEMOS D1 mini) #define PIN_RECEIVER_CS 15 @@ -407,9 +441,9 @@ // RFM95W/SX127x - GPIOxx / CC1101 - RADIOLIB_NC #define PIN_RECEIVER_RST 2 - + #elif defined(ARDUINO_AVR_FEATHER32U4) - // Pinning for Adafruit Feather 32u4 + // Pinning for Adafruit Feather 32u4 #define PIN_RECEIVER_CS 8 // CC1101: GDO0 / RFM95W/SX127x: G0 diff --git a/examples/BresserWeatherSensorMQTTWifiMgr/BresserWeatherSensorMQTTWifiMgr.ino b/examples/BresserWeatherSensorMQTTWifiMgr/BresserWeatherSensorMQTTWifiMgr.ino new file mode 100644 index 00000000..7ac7603e --- /dev/null +++ b/examples/BresserWeatherSensorMQTTWifiMgr/BresserWeatherSensorMQTTWifiMgr.ino @@ -0,0 +1,843 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////// +// BresserWeatherSensorMQTTWifiMgr.ino +// +// Example for BresserWeatherSensorReceiver - +// this is finally a useful application. +// +// At startup, first a WiFi connection and then a connection to the MQTT broker is established. +// (Edit secrets.h accordingly!) +// +// Then receiving data of all sensors (as defined in NUM_SENSORS, see WeatherSensorCfg.h) +// is tried periodically. +// If successful, sensor data is published as MQTT messages, one message per sensor. +// If the sensor ID can be mapped to a name (edit sensor_map[]), this name is used as the +// MQTT topic, otherwise the ID is used. +// From the sensor data, some additional data is calculated and published with the 'extra' topic. +// +// The data topics are published at an interval of >DATA_INTERVAL. +// The 'status' and the 'radio' topics are published at an interval of STATUS_INTERVAL. +// +// If sleep mode is enabled (SLEEP_EN), the device goes into deep sleep mode after data has +// been published. If AWAKE_TIMEOUT is reached before data has been published, deep sleep is +// entered, too. After SLEEP_INTERVAL, the controller is restarted. +// +// +// https://github.com/matthias-bs/BresserWeatherSensorReceiver +// +// Based on: +// arduino-mqtt by Joël Gähwiler (256dpi) (https://github.com/256dpi/arduino-mqtt) +// ArduinoJson by Benoit Blanchon (https://arduinojson.org) +// WiFiManager by tzapu (https://github.com/tzapu/WiFiManager) +// ESP_DoubleResetDetector by Khoi Hoang (https://github.com/khoih-prog/ESP_DoubleResetDetector) +// +// MQTT subscriptions: +// - none - +// +// MQTT publications: +// /data/ sensor data as JSON string - see publishWeatherdata() +// /extra calculated data +// /radio radio transceiver info as JSON string - see publishRadio() +// /status "online"|"offline"|"dead"$ +// +// $ via LWT +// +// +// created: 06/2023 +// +// +// MIT License +// +// Copyright (c) 2023 Matthias Prinke +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// History: +// +// 20230619 Created from BresserWeatherSensorMQTT +// +// ToDo: +// +// - +// +// Notes: +// +// - To enable wakeup from deep sleep on ESP8266, GPIO16 (D0) must be connected to RST! +// Add a jumper to remove this connection for programming! +// - MQTT code based on https://github.com/256dpi/arduino-mqtt +// - For secure MQTT (TLS server verifycation, check the following examples: +// - ESP32: +// https://github.com/espressif/arduino-esp32/blob/master/libraries/WiFiClientSecure/examples/WiFiClientSecure/WiFiClientSecure.ino +// - ESP8266: +// https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/examples/BearSSL_Validation/BearSSL_Validation.ino +// - WiFiManager code based on example AutoConnectwithFSParameters +// - Using ESP_DoubleResetDetector (https://github.com/khoih-prog/ESP_DoubleResetDetector) +// to force WiFiManager reconfiguration +// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#include + +// Library Defines - Need to be defined before library import +#define ESP_DRD_USE_SPIFFS true + +// BEGIN User specific options +//#define LED_EN // Enable LED indicating successful data reception +#define LED_GPIO LED_BUILTIN // LED pin +//#define NUM_SENSORS 1 // Number of sensors to be received +#define TIMEZONE 1 // UTC + TIMEZONE +#define PAYLOAD_SIZE 255 // maximum MQTT message size +#define TOPIC_SIZE 60 // maximum MQTT topic size +#define HOSTNAME_SIZE 30 // maximum hostname size +#define RX_TIMEOUT 90000 // sensor receive timeout [ms] +#define STATUS_INTERVAL 30000 // MQTT status message interval [ms] +#define DATA_INTERVAL 15000 // MQTT data message interval [ms] +#define AWAKE_TIMEOUT 300000 // maximum time until sketch is forced to sleep [ms] +#define SLEEP_INTERVAL 300000 // sleep interval [ms] +#define WIFI_RETRIES 10 // WiFi connection retries +#define WIFI_DELAY 1000 // Delay between connection attempts [ms] +#define SLEEP_EN true // enable sleep mode (see notes above!) +//#define USE_SECUREWIFI // use secure WIFI +#define USE_WIFI // use non-secure WIFI + +#define JSON_CONFIG_FILE "/wifimanager_config.json" + +// Number of seconds after reset during which a +// subseqent reset will be considered a double reset. +#define DRD_TIMEOUT 10 + +// RTC Memory Address for the DoubleResetDetector to use +#define DRD_ADDRESS 0 + + + +// Enable to debug MQTT connection; will generate synthetic sensor data. +//#define _DEBUG_MQTT_ + +// Generate sensor data to test collecting data from multiple sources +//#define GEN_SENSOR_DATA + +// END User specific configuration + +#if ( defined(USE_SECUREWIFI) && defined(USE_WIFI) ) || ( !defined(USE_SECUREWIFI) && !defined(USE_WIFI) ) + #error "Either USE_SECUREWIFI OR USE_WIFI must be defined!" +#endif + +#if defined(ESP32) + #if defined(USE_WIFI) + #include + #elif defined(USE_SECUREWIFI) + #include + #endif +#elif defined(ESP8266) + #include +#endif + + +#include +#include +#ifdef ESP32 + #include +#endif +#include +#include +#include +#include +#include "WeatherSensorCfg.h" +#include "WeatherSensor.h" +#include "WeatherUtils.h" +#include "RainGauge.h" + +const char sketch_id[] = "BresserWeatherSensorMQTTWifiMgr"; + +// Map sensor IDs to Names +SensorMap sensor_map[NUM_SENSORS] = { + {0x39582376, "WeatherSensor"} + //,{0x83750871, "SoilMoisture-1"} +}; + +//enable only one of these below, disabling both is fine too. +// #define CHECK_CA_ROOT +// #define CHECK_PUB_KEY +// Arduino 1.8.19 ESP32 WiFiClientSecure.h: "SHA1 fingerprint is broken now!" +// #define CHECK_FINGERPRINT +////--------------------------//// + +#ifndef SECRETS + const char ssid[] = "WiFiSSID"; + const char pass[] = "WiFiPassword"; + + #define HOSTNAME "ESPWeather" + #define APPEND_CHIP_ID + + // define your default values here, if there are different values in config.json, they are overwritten. + char mqtt_host[40]; + char mqtt_port[6] = "1883"; + char mqtt_user[21] = ""; + char mqtt_pass[21] = ""; + + + #ifdef CHECK_CA_ROOT + static const char digicert[] PROGMEM = R"EOF( + -----BEGIN CERTIFICATE----- + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + -----END CERTIFICATE----- + )EOF"; + #endif + + #ifdef CHECK_PUB_KEY + // Extracted by: openssl x509 -pubkey -noout -in fullchain.pem + static const char pubkey[] PROGMEM = R"KEY( + -----BEGIN PUBLIC KEY----- + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxx + -----END PUBLIC KEY----- + )KEY"; + #endif + + #ifdef CHECK_FINGERPRINT + // Extracted by: openssl x509 -fingerprint -in fillchain.pem + static const char fp[] PROGMEM = "AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD"; + #endif +#endif + +DoubleResetDetector *drd; + +// flag for saving data +bool shouldSaveConfig = false; + +// flag for forcing WiFiManager re-config +bool forceConfig = false; + +WeatherSensor weatherSensor; +RainGauge rainGauge; + +// MQTT topics +const char MQTT_PUB_STATUS[] = "/status"; +const char MQTT_PUB_RADIO[] = "/radio"; +const char MQTT_PUB_DATA[] = "/data"; +const char MQTT_PUB_EXTRA[] = "/extra"; + +char mqttPubStatus[TOPIC_SIZE]; +char mqttPubRadio[TOPIC_SIZE]; +char mqttPubData[TOPIC_SIZE]; +char mqttPubExtra[TOPIC_SIZE]; +char Hostname[HOSTNAME_SIZE]; + +////////////////////////////////////////////////////// + +#if (defined(CHECK_PUB_KEY) and defined(CHECK_CA_ROOT)) or (defined(CHECK_PUB_KEY) and defined(CHECK_FINGERPRINT)) or (defined(CHECK_FINGERPRINT) and defined(CHECK_CA_ROOT)) or (defined(CHECK_PUB_KEY) and defined(CHECK_CA_ROOT) and defined(CHECK_FINGERPRINT)) +#error "cant have both CHECK_CA_ROOT and CHECK_PUB_KEY enabled" +#endif + +// Generate WiFi network instance +#if defined(ESP32) + #if defined(USE_WIFI) + WiFiClient net; + #elif defined(USE_SECUREWIFI) + WiFiClientSecure net; + #endif +#elif defined(ESP8266) + #if defined(USE_WIFI) + WiFiClient net; + #elif defined(USE_SECUREWIFI) + BearSSL::WiFiClientSecure net; + #endif +#endif + + +// +// Generate MQTT client instance +// N.B.: Default message buffer size is too small! +// +MQTTClient client(PAYLOAD_SIZE); + +uint32_t lastMillis = 0; +uint32_t statusPublishPreviousMillis = 0; +time_t now; + +void publishWeatherdata(bool complete = false); +void mqtt_connect(void); + +/*! + * \brief Callback notifying us of the need to save config + */ +void saveConfigCallback() +{ + Serial.println("Should save config"); + shouldSaveConfig = true; +} + + +/*! + * \brief Wait for WiFi connection + */ +void wifi_wait(int wifi_retries, int wifi_delay) +{ + int count = 0; + while (WiFi.status() != WL_CONNECTED) { + Serial.print("."); + delay(wifi_delay); + if (++count == wifi_retries) { + Serial.printf("WiFi connection timed out, will restart after %d s\n", SLEEP_INTERVAL/1000); + ESP.deepSleep(SLEEP_INTERVAL * 1000); + } + } +} + + +/*! + * \brief WiFiManager Setup + * + * Configures WiFi access point and MQTT connection parameters + */ +void wifimgr_setup(void) +{ + + // clean FS, for testing + //SPIFFS.format(); + + // read configuration from FS json + Serial.println("mounting FS..."); + + if (SPIFFS.begin()) { + Serial.println("mounted file system"); + if (SPIFFS.exists("/config.json")) { + // file exists, reading and loading + Serial.println("reading config file"); + File configFile = SPIFFS.open("/config.json", "r"); + if (configFile) { + Serial.println("opened config file"); + size_t size = configFile.size(); + // Allocate a buffer to store contents of the file. + std::unique_ptr buf(new char[size]); + + configFile.readBytes(buf.get(), size); + + DynamicJsonDocument json(1024); + auto deserializeError = deserializeJson(json, buf.get()); + serializeJson(json, Serial); + + if ( ! deserializeError ) { + Serial.println("\nparsed json"); + strcpy(mqtt_host, json["mqtt_server"]); + strcpy(mqtt_port, json["mqtt_port"]); + strcpy(mqtt_user, json["mqtt_user"]); + strcpy(mqtt_pass, json["mqtt_pass"]); + } else { + Serial.println("failed to load json config"); + } + configFile.close(); + } + } + } else { + Serial.println("failed to mount FS"); + } + //end read + + //WiFi.disconnect(); + WiFi.hostname(Hostname); + WiFi.mode(WIFI_STA); // explicitly set mode, esp defaults to STA+AP + delay(10); + + // wm.resetSettings(); // wipe settings + + // The extra parameters to be configured (can be either global or just in the setup) + // After connecting, parameter.getValue() will get you the configured value + // id/name placeholder/prompt default length + WiFiManagerParameter custom_mqtt_server("server", "MQTT Server (Broker)", mqtt_host, 40); + WiFiManagerParameter custom_mqtt_port("port", "MQTT Port", mqtt_port, 6); + WiFiManagerParameter custom_mqtt_user("user", "MQTT Username", mqtt_user, 20); + WiFiManagerParameter custom_mqtt_pass("pass", "MQTT Password", mqtt_pass, 20); + + WiFiManager wifiManager; + + if (forceConfig) { + wifiManager.resetSettings(); + } + + // set config save notify callback + wifiManager.setSaveConfigCallback(saveConfigCallback); + + // set static ip + //wifiManager.setSTAStaticIPConfig(IPAddress(10, 0, 1, 99), IPAddress(10, 0, 1, 1), IPAddress(255, 255, 255, 0)); + + // add all your parameters here + wifiManager.addParameter(&custom_mqtt_server); + wifiManager.addParameter(&custom_mqtt_port); + wifiManager.addParameter(&custom_mqtt_user); + wifiManager.addParameter(&custom_mqtt_pass); + + // Options + // reset settings - for testing + //wifiManager.resetSettings(); + + // set minimum quality of signal so it ignores AP's under that quality + // defaults to 8% + //wifiManager.setMinimumSignalQuality(); + + // sets timeout until configuration portal gets turned off + // useful to make it all retry or go to sleep + // in seconds + wifiManager.setTimeout(120); + + // fetches ssid and pass and tries to connect + // if it does not connect it starts an access point with the specified name + // and goes into a blocking loop awaiting configuration + if (!wifiManager.autoConnect(Hostname, "password")) { + Serial.println("failed to connect and hit timeout"); + delay(3000); + //reset and try again, or maybe put it to deep sleep + ESP.restart(); + delay(5000); + } + + // if you get here you have connected to the WiFi + Serial.println("connected...yeey :)"); + + // read updated parameters + strcpy(mqtt_host, custom_mqtt_server.getValue()); + strcpy(mqtt_port, custom_mqtt_port.getValue()); + strcpy(mqtt_user, custom_mqtt_user.getValue()); + strcpy(mqtt_pass, custom_mqtt_pass.getValue()); + Serial.println("The values in the file are: "); + Serial.println("\tmqtt_server : " + String(mqtt_host)); + Serial.println("\tmqtt_port : " + String(mqtt_port)); + Serial.println("\tmqtt_user : " + String(mqtt_user)); + Serial.println("\tmqtt_pass : ***"); + + // save the custom parameters to FS + if (shouldSaveConfig) { + Serial.println("saving config"); + + DynamicJsonDocument json(1024); + json["mqtt_server"] = mqtt_host; + json["mqtt_port"] = mqtt_port; + json["mqtt_user"] = mqtt_user; + json["mqtt_pass"] = mqtt_pass; + + File configFile = SPIFFS.open("/config.json", "w"); + if (!configFile) { + Serial.println("failed to open config file for writing"); + } + + serializeJson(json, Serial); + serializeJson(json, configFile); + + configFile.close(); + //end save + } + + Serial.println("local ip"); + Serial.println(WiFi.localIP()); +} + + +/*! + * \brief Setup secure WiFi (if enabled) and MQTT client + */ + void mqtt_setup(void) +{ + #ifdef USE_SECUREWIFI + // Note: TLS security needs correct time + Serial.print("Setting time using SNTP "); + configTime(TIMEZONE * 3600, 0, "pool.ntp.org", "time.nist.gov"); + now = time(nullptr); + while (now < 1510592825) + { + delay(500); + Serial.print("."); + now = time(nullptr); + } + Serial.println("done!"); + struct tm timeinfo; + gmtime_r(&now, &timeinfo); + Serial.print("Current time: "); + Serial.println(asctime(&timeinfo)); + + #ifdef CHECK_CA_ROOT + BearSSL::X509List cert(digicert); + net.setTrustAnchors(&cert); + #endif + #ifdef CHECK_PUB_KEY + BearSSL::PublicKey key(pubkey); + net.setKnownKey(&key); + #endif + #ifdef CHECK_FINGERPRINT + net.setFingerprint(fp); + #endif + #if (!defined(CHECK_PUB_KEY) and !defined(CHECK_CA_ROOT) and !defined(CHECK_FINGERPRINT)) + // do not verify tls certificate + net.setInsecure(); + #endif + #endif + client.begin(mqtt_host, atoi(mqtt_port), net); + + // set up MQTT receive callback (if required) + //client.onMessage(messageReceived); + client.setWill(mqttPubStatus, "dead", true /* retained*/, 1 /* qos */); + mqtt_connect(); +} + + +/*! + * \brief (Re-)Connect to WLAN and connect MQTT broker + */ +void mqtt_connect(void) +{ + Serial.print(F("Checking wifi...")); + wifi_wait(WIFI_RETRIES, WIFI_DELAY); + + Serial.print(F("\nMQTT connecting... ")); + while (!client.connect(Hostname, mqtt_user, mqtt_pass)) + { + Serial.print("."); + delay(1000); + } + + Serial.println(F("connected!")); + //client.subscribe(MQTT_SUB_IN); + Serial.printf("%s: %s\n", mqttPubStatus, "online"); + client.publish(mqttPubStatus, "online"); +} + + +// +// MQTT message received callback +// +/* +void messageReceived(String &topic, String &payload) +{ +} +*/ + + + +/*! + \brief Publish weather data as MQTT message + + \param complete Indicate that entire data is complete, regardless of the flags temp_ok/wind_ok/rain_ok + (which reflect only the state of the last message) +*/ +void publishWeatherdata(bool complete) +{ + char mqtt_payload[PAYLOAD_SIZE]; // sensor data + char mqtt_payload2[PAYLOAD_SIZE]; // calculated extra data + char mqtt_topic[TOPIC_SIZE+31]; // add space for ID/name + + // ArduinoJson does not allow to set number of decimals for floating point data - + // neither does MQTT Dashboard... + // Therefore the JSON string is created manually. + + for (int i=0; i 2) { + Serial.printf("%s: %s\n", mqttPubExtra, mqtt_payload2); + client.publish(mqttPubExtra, mqtt_payload2, false, 0); + } + } // for (int i=0; i> (40 - i)) & 0xff) << i; + } + snprintf(&Hostname[strlen(Hostname)], HOSTNAME_SIZE, "-%06X", chipId); + #elif defined(APPEND_CHIP_ID) && defined(ESP8266) + snprintf(&Hostname[strlen(Hostname)], HOSTNAME_SIZE, "-%06X", ESP.getChipId() & 0xFFFFFF); + #endif + + snprintf(mqttPubStatus, TOPIC_SIZE, "%s%s", Hostname, MQTT_PUB_STATUS); + snprintf(mqttPubRadio, TOPIC_SIZE, "%s%s", Hostname, MQTT_PUB_RADIO); + snprintf(mqttPubData, TOPIC_SIZE, "%s%s", Hostname, MQTT_PUB_DATA); + snprintf(mqttPubExtra, TOPIC_SIZE, "%s%s", Hostname, MQTT_PUB_EXTRA); + + drd = new DoubleResetDetector(DRD_TIMEOUT, DRD_ADDRESS); + if (drd->detectDoubleReset()) + { + Serial.println(F("Forcing config mode as there was a Double reset detected")); + forceConfig = true; + } +/* + bool spiffsSetup = loadConfigFile(); + if (!spiffsSetup) + { + Serial.println(F("Forcing config mode as there is no saved config")); + forceConfig = true; + } +*/ + wifimgr_setup(); + mqtt_setup(); + weatherSensor.begin(); +} + + +/*! + \brief Wrapper which allows passing of member function as parameter +*/ +void clientLoopWrapper(void) +{ + client.loop(); + drd->loop(); +} + + +// +// Main execution loop +// +void loop() { + drd->loop(); + if (WiFi.status() != WL_CONNECTED) + { + Serial.print(F("Checking wifi")); + while (WiFi.waitForConnectResult() != WL_CONNECTED) + { + WiFi.begin(ssid, pass); + Serial.print("."); + delay(10); + } + Serial.println(F("connected")); + } + else + { + if (!client.connected()) + { + mqtt_connect(); + } + else + { + client.loop(); + } + } + + const uint32_t currentMillis = millis(); + if (currentMillis - statusPublishPreviousMillis >= STATUS_INTERVAL) { + // publish a status message @STATUS_INTERVAL + statusPublishPreviousMillis = currentMillis; + Serial.printf("%s: %s\n", mqttPubStatus, "online"); + client.publish(mqttPubStatus, "online"); + publishRadio(); + } + + bool decode_ok = false; + #ifdef _DEBUG_MQTT_ + decode_ok = weatherSensor.genMessage(0 /* slot */, 0x01234567 /* ID */, 1 /* type */, 0 /* channel */); + #else + // Clear sensor data buffer + weatherSensor.clearSlots(); + + #ifdef GEN_SENSOR_DATA + weatherSensor.genMessage(1 /* slot */, 0xdeadbeef /* ID */, 1 /* type */, 7 /* channel */); + #endif + + // Attempt to receive data set with timeout of s + decode_ok = weatherSensor.getData(RX_TIMEOUT, DATA_COMPLETE, 0, &clientLoopWrapper); + #endif + + #ifdef LED_EN + if (decode_ok) { + digitalWrite(LED_GPIO, LOW); + } else { + digitalWrite(LED_GPIO, HIGH); + } + #endif + + // publish a data message @DATA_INTERVAL + if (millis() - lastMillis > DATA_INTERVAL) { + lastMillis = millis(); + if (decode_ok) + publishWeatherdata(false); + } + + bool force_sleep = millis() > AWAKE_TIMEOUT; + + // Go to sleep only after complete set of data has been sent + if (SLEEP_EN && (decode_ok || force_sleep)) { + #ifdef _DEBUG_MODE_ + if (force_sleep) { + Serial.println(F("Awake time-out!")); + } else { + Serial.println(F("Data forwarding completed.")); + } + #endif + Serial.printf("Sleeping for %d ms\n", SLEEP_INTERVAL); + Serial.printf("%s: %s\n", mqttPubStatus, "offline"); + Serial.flush(); + client.publish(mqttPubStatus, "offline", true /* retained */, 0 /* qos */); + client.disconnect(); + client.loop(); + #ifdef LED_EN + pinMode(LED_GPIO, INPUT); + #endif + ESP.deepSleep(SLEEP_INTERVAL * 1000); + } +} // loop() diff --git a/library.properties b/library.properties index 265798d4..bebabf95 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=BresserWeatherSensorReceiver -version=0.8.0 +version=0.10.0 author=Matthias Prinke maintainer=Matthias Prinke sentence=Bresser 5-in-1/6-in-1/7-in-1 868 MHz Weather Sensor Radio Receiver for Arduino based on CC1101 or SX1276/RFM95W. diff --git a/package.json b/package.json index e3bf50c7..f3c1b6e0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "BresserWeatherSensorReceiver", - "version": "0.8.0", + "version": "0.10.0", "description": "Bresser 5-in-1/6-in-1/7-in-1 868 MHz Weather Sensor Radio Receiver for Arduino based on CC1101 or SX1276/RFM95W", "main": "WeatherSensor.cpp", "frameworks": "arduino", @@ -19,9 +19,11 @@ }, "homepage": "https://github.com/matthias-bs/BresserWeatherSensorReceiver#README", "dependencies": { - "RadioLib": "jgromes/RadioLib#semver:^6.0.0", + "RadioLib": "jgromes/RadioLib#semver:^6.1.0", "lora-serialization": "thesolarnomad/lora-serialization#semver:^3.1.0", - "arduino-mqtt": "256dpi/arduino-mqtt#semver:^2.5.1" - "ArduinoJson": "bblanchon/ArduinoJson#semver:^6.21.2" + "arduino-mqtt": "256dpi/arduino-mqtt#semver:^2.5.1", + "ArduinoJson": "bblanchon/ArduinoJson#semver:^6.21.2", + "WiFiManager": "tzapu/WiFiManager#semver:2.0.16-rc.2", + "ESP_DoubleResetDetector": "khoih-prog/ESP_DoubleResetDetector#semver:1.3.2" } } diff --git a/src/WeatherSensor.cpp b/src/WeatherSensor.cpp index 4626d8c3..b753df0a 100644 --- a/src/WeatherSensor.cpp +++ b/src/WeatherSensor.cpp @@ -57,7 +57,10 @@ // 20230228 Added Bresser 7 in 1 decoder by Jorge Navarro-Ortiz (jorgenavarro@ugr.es) // 20230329 Fixed issue introduced with 7 in 1 decoder // 20230412 Added workaround for Professional Wind Gauge / Anemometer, P/N 7002531 +// 20230412 Fixed 7 in 1 decoder (valid/complete flags were not set) // 20230624 Added Bresser Lightning Sensor decoder +// 20230613 Fixed rain value in 7 in 1 decoder +// 20230708 Added startup flag in 6-in-1 and 7-in-1 decoder; added sensor type in 7-in-1 decoder // // ToDo: // - @@ -523,6 +526,7 @@ DecodeStatus WeatherSensor::decodeBresser5In1Payload(uint8_t *msg, uint8_t msgSi sensor[slot].sensor_id = id_tmp; sensor[slot].s_type = type_tmp; + sensor[slot].startup = false; // To Do int temp_raw = (msg[20] & 0x0f) + ((msg[20] & 0xf0) >> 4) * 10 + (msg[21] &0x0f) * 100; if (msg[25] & 0x0f) { @@ -603,7 +607,7 @@ DecodeStatus WeatherSensor::decodeBresser5In1Payload(uint8_t *msg, uint8_t msgSi // Moisture: // // f16e 187000e34 7 ffffff0000 252 2 16 fff 004 000 [25,2, 99%, CH 7] -// DIGEST:8h8h ID?8h8h8h8h STYPE:4h STARTUP:1b CH:3d 8h 8h8h 8h8h TEMP:12h ?2b BATT:1b ?1b MOIST:8h UV?~12h ?4h CHKSUM:8h +// DIGEST:8h8h ID?8h8h8h8h :4h STARTUP:1b CH:3d 8h 8h8h 8h8h TEMP:12h ?2b BATT:1b ?1b MOIST:8h UV?~12h ?4h CHKSUM:8h // // Moisture is transmitted in the humidity field as index 1-16: 0, 7, 13, 20, 27, 33, 40, 47, 53, 60, 67, 73, 80, 87, 93, 99. // The Wind speed and direction fields decode to valid zero but we exclude them from the output. @@ -641,8 +645,8 @@ DecodeStatus WeatherSensor::decodeBresser5In1Payload(uint8_t *msg, uint8_t msgSi // // Wind and Temperature/Humidity or Rain: // -// DIGEST:8h8h ID:8h8h8h8h STYPE:4h STARTUP:1b CH:3d WSPEED:~8h~4h ~4h~8h WDIR:12h ?4h TEMP:8h.4h ?2b BATT:1b ?1b HUM:8h UV?~12h ?4h CHKSUM:8h -// DIGEST:8h8h ID:8h8h8h8h STYPE:4h STARTUP:1b CH:3d WSPEED:~8h~4h ~4h~8h WDIR:12h ?4h RAINFLAG:8h RAIN:8h8h UV:8h8h CHKSUM:8h +// DIGEST:8h8h ID:8h8h8h8h :4h STARTUP:1b CH:3d WSPEED:~8h~4h ~4h~8h WDIR:12h ?4h TEMP:8h.4h ?2b BATT:1b ?1b HUM:8h UV?~12h ?4h CHKSUM:8h +// DIGEST:8h8h ID:8h8h8h8h :4h STARTUP:1b CH:3d WSPEED:~8h~4h ~4h~8h WDIR:12h ?4h RAINFLAG:8h RAIN:8h8h UV:8h8h CHKSUM:8h // // Digest is LFSR-16 gen 0x8810 key 0x5412, excluding the add-checksum and trailer. // Checksum is 8-bit add (with carry) to 0xff. @@ -708,12 +712,10 @@ DecodeStatus WeatherSensor::decodeBresser6In1Payload(uint8_t *msg, uint8_t msgSi if (status != DECODE_OK) return status; - // unused... - //int startup = (msg[6] >> 3) & 1; // s.a. #1214 - sensor[slot].sensor_id = id_tmp; sensor[slot].s_type = type_tmp; sensor[slot].chan = chan_tmp; + sensor[slot].startup = (msg[6] >> 3) & 1; // s.a. #1214 f_3in1 = is_decode3in1(id_tmp); @@ -873,8 +875,7 @@ DecodeStatus WeatherSensor::decodeBresser7In1Payload(uint8_t *msg, uint8_t msgSi int wdir = (msgw[4] >> 4) * 100 + (msgw[4] & 0x0f) * 10 + (msgw[5] >> 4); int wgst_raw = (msgw[7] >> 4) * 100 + (msgw[7] & 0x0f) * 10 + (msgw[8] >> 4); int wavg_raw = (msgw[8] & 0x0f) * 100 + (msgw[9] >> 4) * 10 + (msgw[9] & 0x0f); - //int rain_raw = (msgw[10] >> 4) * 100000 + (msgw[10] & 0x0f) * 10000 + (msgw[11] >> 4) * 1000 + (msgw[11] & 0x0f) * 100 + (msgw[12] >> 4) * 10 + (msgw[12] & 0x0f) * 1; // 6 digits - int rain_raw = (msgw[10] >> 4) * 1000 + (msgw[10] & 0x0f) * 100 + (msgw[11] >> 4) * 10 + (msgw[11] & 0x0f) * 1; // 4 digits + int rain_raw = (msgw[10] >> 4) * 100000 + (msgw[10] & 0x0f) * 10000 + (msgw[11] >> 4) * 1000 + (msgw[11] & 0x0f) * 100 + (msgw[12] >> 4) * 10 + (msgw[12] & 0x0f) * 1; // 6 digits float rain_mm = rain_raw * 0.1f; int temp_raw = (msgw[14] >> 4) * 100 + (msgw[14] & 0x0f) * 10 + (msgw[15] >> 4); float temp_c = temp_raw * 0.1f; @@ -900,6 +901,8 @@ DecodeStatus WeatherSensor::decodeBresser7In1Payload(uint8_t *msg, uint8_t msgSi sensor[slot].uv_ok = true; sensor[slot].sensor_id = id_tmp; + sensor[slot].s_type = msgw[6] >> 4; + sensor[slot].startup = (msgw[6] & 0x08) == 0x08; sensor[slot].temp_c = temp_c; sensor[slot].humidity = humidity; #ifdef WIND_DATA_FLOATINGPOINT @@ -917,6 +920,8 @@ DecodeStatus WeatherSensor::decodeBresser7In1Payload(uint8_t *msg, uint8_t msgSi sensor[slot].light_lux = light_lux; sensor[slot].uv = uv_index; sensor[slot].battery_ok = !battery_low; + sensor[slot].valid = true; + sensor[slot].complete = true; sensor[slot].rssi = rssi; sensor[slot].valid = true; sensor[slot].complete = true; diff --git a/src/WeatherSensor.h b/src/WeatherSensor.h index 7e12ff6b..e1104819 100644 --- a/src/WeatherSensor.h +++ b/src/WeatherSensor.h @@ -56,6 +56,7 @@ // 20230330 Added changes for Adafruit Feather 32u4 LoRa Radio // 20230412 Added workaround for Professional Wind Gauge / Anemometer, P/N 7002531 // 20230624 Added Bresser Lightning Sensor decoder +// 20230708 Added SENSOR_TYPE_WEATHER_7IN1 and startup flag // // ToDo: // - @@ -80,6 +81,7 @@ // 3 - Lightning Sensor PN 7009976 // 4 - Soil Moisture Sensor 6-in-1; PN 7009972 // 9 - Professional Rain Gauge (5-in-1 decoder) +// 11 - Weather Sensor 7-in-1 7-in-1; PN 7003300 // ? - Air Quality Sensor // ? - Water Leakage Sensor // ? - Pool Thermometer @@ -89,6 +91,7 @@ #define SENSOR_TYPE_LIGHTNING 3 // Lightning Sensor #define SENSOR_TYPE_SOIL 4 // Soil Temperature and Moisture (from 6-in-1 decoder) #define SENSOR_TYPE_RAIN 9 // Professional Rain Gauge (from 5-in-1 decoder) +#define SENSOR_TYPE_WEATHER_7IN1 11 // Weather Sensor 7-in-1 // Sensor specific rain gauge overflow threshold (mm) @@ -184,6 +187,7 @@ class WeatherSensor { uint32_t sensor_id; //!< sensor ID (5-in-1: 1 byte / 6-in-1: 4 bytes) uint8_t s_type; //!< sensor type (only 6-in1) uint8_t chan; //!< channel (only 6-in-1) + bool startup = false; //!< startup after reset / battery change bool valid; //!< data valid (but not necessarily complete) bool complete; //!< data is split into two separate messages is complete (only 6-in-1 WS) bool temp_ok = false; //!< temperature o.k. (only 6-in-1) diff --git a/src/WeatherSensorCfg.h b/src/WeatherSensorCfg.h index 7638ed44..85828031 100644 --- a/src/WeatherSensorCfg.h +++ b/src/WeatherSensorCfg.h @@ -42,6 +42,7 @@ // 20230330 Added pin definitions and changes for Adafruit Feather 32u4 (AVR) RFM95 LoRa Radio // 20230412 Added workaround for Professional Wind Gauge / Anemometer, P/N 7002531 // 20230420 Added pin definitions for DFRobot FireBeetle ESP32 with FireBeetle Cover LoRa +// 20230607 Added pin definitions for Heltec WiFi LoRa 32(V2) // 20230624 Added Bresser Lightning Sensor decoder // // ToDo: @@ -82,6 +83,10 @@ // in the Arduino IDE: //#define ARDUINO_heltec_wireless_stick +// This define is set by selecting "Board: Heltec WiFi LoRa 32(V2)" +// in the Adruino IDE: +//#define ARDUINO_heltec_wifi_lora_32_V2 + // Adafruit Feather ESP32S2 with RFM95W "FeatherWing" ADA3232 // https://github.com/espressif/arduino-esp32/blob/master/variants/adafruit_feather_esp32s2/pins_arduino.h // @@ -117,6 +122,10 @@ #pragma message("ARDUINO_heltec_wireless_stick defined; using on-board transceiver") #define USE_SX1276 +#elif defined(ARDUINO_heltec_wifi_lora_32_V2) + #pragma message("ARDUINO_heltec_wifi_lora_32_V2 defined; using on-board transceiver") + #define USE_SX1276 + #elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32S2) #pragma message("ARDUINO_ADAFRUIT_FEATHER_ESP32S2 defined; assuming RFM95W FeatherWing will be used") #define USE_SX1276 @@ -127,7 +136,7 @@ #pragma message("Required wiring: A to RST, B to DIO1, D to DIO0, E to CS") #elif defined(ARDUINO_AVR_FEATHER32U4) - #pragma message("ARDUINO_AVR_FEATHER32U4 defined; assuming this is the Arduino Feather 32u4 RFM95 LoRa Radio") + #pragma message("ARDUINO_AVR_FEATHER32U4 defined; assuming this is the Adafruit Feather 32u4 RFM95 LoRa Radio") #define USE_SX1276 #elif defined(ARDUINO_ESP32_DEV) @@ -370,8 +379,8 @@ // RFM95W/SX127x - GPIOxx / CC1101 - RADIOLIB_NC #define PIN_RECEIVER_RST LORA_RST -#elif defined(ARDUINO_heltec_wireless_stick) - // Use pinning for Heltec Wireless Stick +#elif defined(ARDUINO_heltec_wireless_stick) || defined(ARDUINO_heltec_wifi_lora_32_V2) + // Use pinning for Heltec Wireless Stick or WiFi LoRa32 V2, respectively #define PIN_RECEIVER_CS SS // CC1101: GDO0 / RFM95W/SX127x: G0 diff --git a/src/WeatherSensorCfg.h.template b/src/WeatherSensorCfg.h.template index 0a83cf9a..eb65ebeb 100644 --- a/src/WeatherSensorCfg.h.template +++ b/src/WeatherSensorCfg.h.template @@ -42,6 +42,7 @@ // 20230330 Added pin definitions and changes for Adafruit Feather 32u4 (AVR) RFM95 LoRa Radio // 20230412 Added workaround for Professional Wind Gauge / Anemometer, P/N 7002531 // 20230420 Added pin definitions for DFRobot FireBeetle ESP32 with FireBeetle Cover LoRa +// 20230607 Added pin definitions for Heltec WiFi LoRa 32(V2) // // ToDo: // - @@ -81,6 +82,10 @@ // in the Arduino IDE: //#define ARDUINO_heltec_wireless_stick +// This define is set by selecting "Board: Heltec WiFi LoRa 32(V2)" +// in the Adruino IDE: +//#define ARDUINO_heltec_wifi_lora_32_V2 + // Adafruit Feather ESP32S2 with RFM95W "FeatherWing" ADA3232 // https://github.com/espressif/arduino-esp32/blob/master/variants/adafruit_feather_esp32s2/pins_arduino.h // @@ -116,6 +121,10 @@ #pragma message("ARDUINO_heltec_wireless_stick defined; using on-board transceiver") #define USE_SX1276 +#elif defined(ARDUINO_heltec_wifi_lora_32_V2) + #pragma message("ARDUINO_heltec_wifi_lora_32_V2 defined; using on-board transceiver") + #define USE_SX1276 + #elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32S2) #pragma message("ARDUINO_ADAFRUIT_FEATHER_ESP32S2 defined; assuming RFM95W FeatherWing will be used") #define USE_SX1276 @@ -125,15 +134,27 @@ #define USE_SX1276 #pragma message("Required wiring: A to RST, B to DIO1, D to DIO0, E to CS") -#elif defined(ARDUINO_ESP32_DEV) - #pragma message("Generic ESP32; assuming this is the LoRaWAN_Node board (DFRobot Firebeetle32 + Adafruit RFM95W LoRa Radio)") - #define LORAWAN_NODE - #define USE_SX1276 - #elif defined(ARDUINO_AVR_FEATHER32U4) - #pragma message("ARDUINO_AVR_FEATHER32U4 defined; assuming this is the Arduino Feather 32u4 RFM95 LoRa Radio") + #pragma message("ARDUINO_AVR_FEATHER32U4 defined; assuming this is the Adafruit Feather 32u4 RFM95 LoRa Radio") #define USE_SX1276 - + +#elif defined(ARDUINO_ESP32_DEV) + //#define LORAWAN_NODE + #define FIREBEETLE_ESP32_COVER_LORA + + #if !defined(LORAWAN_NODE) && !defined(FIREBEETLE_ESP32_COVER_LORA) + #pragma message("ARDUINO_ESP32_DEV defined; select either LORAWAN_NODE or FIREBEETLE_ESP32_COVER_LORA manually!") + + #elif defined(LORAWAN_NODE) + #pragma message("LORAWAN_NODE defined; assuming this is the LoRaWAN_Node board (DFRobot Firebeetle32 + Adafruit RFM95W LoRa Radio)") + #define USE_SX1276 + + #elif defined(FIREBEETLE_ESP32_COVER_LORA) + #define USE_SX1276 + #pragma message("FIREBEETLE_ESP32_COVER_LORA defined; assuming this is a FireBeetle ESP32 with FireBeetle Cover LoRa") + #pragma message("Required wiring: D2 to RESET, D3 to DIO0, D4 to CS, D5 to DIO1") + + #endif #endif @@ -219,6 +240,7 @@ #endif + // Replacement for // https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-log.h // on Arduino AVR: @@ -315,6 +337,18 @@ // RFM95W/SX127x - GPIOxx / CC1101 - RADIOLIB_NC #define PIN_RECEIVER_RST 12 +#elif defined(FIREBEETLE_ESP32_COVER_LORA) + #define PIN_RECEIVER_CS 27 // D4 + + // CC1101: GDO0 / RFM95W/SX127x: G0 + #define PIN_RECEIVER_IRQ 26 // D3 + + // CC1101: GDO2 / RFM95W/SX127x: G1 + #define PIN_RECEIVER_GPIO 9 // D5 + + // RFM95W/SX127x - GPIOxx / CC1101 - RADIOLIB_NC + #define PIN_RECEIVER_RST 25 // D2 + #elif defined(ARDUINO_TTGO_LoRa32_V1) || defined(ARDUINO_TTGO_LoRa32_V2) // Use pinning for LILIGO TTGO LoRa32-OLED #define PIN_RECEIVER_CS LORA_CS @@ -343,8 +377,8 @@ // RFM95W/SX127x - GPIOxx / CC1101 - RADIOLIB_NC #define PIN_RECEIVER_RST LORA_RST -#elif defined(ARDUINO_heltec_wireless_stick) - // Use pinning for Heltec Wireless Stick +#elif defined(ARDUINO_heltec_wireless_stick) || defined(ARDUINO_heltec_wifi_lora_32_V2) + // Use pinning for Heltec Wireless Stick or WiFi LoRa32 V2, respectively #define PIN_RECEIVER_CS SS // CC1101: GDO0 / RFM95W/SX127x: G0 @@ -394,7 +428,7 @@ // RFM95W/SX127x - GPIOxx / CC1101 - RADIOLIB_NC #define PIN_RECEIVER_RST 32 - + #elif defined(ESP8266) // Generic pinning for ESP8266 development boards (e.g. LOLIN/WEMOS D1 mini) #define PIN_RECEIVER_CS 15 @@ -407,9 +441,9 @@ // RFM95W/SX127x - GPIOxx / CC1101 - RADIOLIB_NC #define PIN_RECEIVER_RST 2 - + #elif defined(ARDUINO_AVR_FEATHER32U4) - // Pinning for Adafruit Feather 32u4 + // Pinning for Adafruit Feather 32u4 #define PIN_RECEIVER_CS 8 // CC1101: GDO0 / RFM95W/SX127x: G0