Marco Zonca
Published © GPL3+

Weather station Bresser to WUNDERGROUND and/or APRS

Connects a Bresser 7in1 weather station and publishes sensors data to Wunderground and/or APRS servers. It uses LilyGO Lora32 OLED v. 1.6.1.

IntermediateFull instructions provided35
Weather station Bresser to WUNDERGROUND and/or APRS

Things used in this project

Hardware components

LILYGO® TTGO LoRa32 T3 V1.6.1
LILYGO® TTGO LoRa32 T3 V1.6.1
×1

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)

Story

Read more

Custom parts and enclosures

Back panel 3D .STL

Sketchfab still processing.

Box 3D .STL

Sketchfab still processing.

Front panel 3D .STL

Sketchfab still processing.

Schematics

Schematic diagram

Code

Arduino code (sketch)

Arduino
/*
  ard-wunderbresser by Marco Zonca 12/2025, ver. 1.0
  
  this sketch reads Bresser 7-in-1 weather station sensors by the way of LoRa radio on 868Mhz using
  LilyGO TTGO LoRa32 T3 1.6.1. (OLED display, micro SD, WiFi, BLE, sx1276); additionally I added an i2c
  BME280 pressure/temperature/humidity sensor board and a buzzer; it does data upload to Wunderground.com
  website using PWS Protocol via WiFi "https://support.weather.com/s/article/PWS-Upload-Protocol";
  it does aswell upload to APRS network as ham radio operator (a proper licence is required or your have
  to use a citizen code to send data freely, read https://aprs.fi/doc/guide/guide.html);
  
  it shows failures counters on the display and in case of repeating errors receiving from the weather station,
  from NTP server, BME board, or transmitting with WiFi to Wunderground or APRS the buzzer plays an alarm;
  the failures counters are resetted every day at 00:00;

    Counters shown/display: Time:  NTP update missed via network
                            Bress: Bresser weather station missed, or wrong data reception via radio 868Mhz
                            BME:   BME280 sensor board missed or wrong data via I2C
                            AR:    APRS server refused connection or bad response from it
                            Rb:    Reboot unexpected, i.e. by watchdog
                            WG:    Wunderground server refused connection or bad response from it
                            WF:    WiFi failed to connect to the network

  - the circuit works at 3.3v i/o level; it is powered by USB with a consumption around 55-90mA, in case of 
    blackout it just power down like your WiFi access point, the weather station is battery powered; 
    if you like to keep the circuit on during blackouts you have to add a rechargeable battery using the onboard
    2 pins connector, the USB will provide to recharge it as the MCU board already got a recharging circuit; a battery
    model 102535 850/1050 mA/h fits perfectly with my 3D printed enclosure, be sure the connector is a 2 pin JST 1.25mm
    and the (+) and (-) wires are correct; 

  - my experience says to avoid to put the circuit too close to the WiFi access point (1-2m away is fine), in this
    way you will have less communication errors;

  - special care is taken for some calculation as per the normalized air pressure, the average wind direction,
    and the dew point, thanks to Google AI :-). It is active a watchdog so in case of software stuck it will
    restart after 60"; the display will be off after 10 minutes, you may read failure counters in APRS raw packets
    in the "Comment", aswell for weather station battery status;
  
  - using mac osx and Arduino IDE, to upload the sketch maybe you have to install the USB serial driver for this
    circuit, more info here: https://www.wch-ic.com/downloads/CH34XSER_MAC_ZIP.html
    
  - Before compiling and testing you have to specify your Access Point name and Password for your WiFi:
  
    char WiFi_SSID[40] = "XXXXX";  // put your SSID WiFi access point in the code
    char WiFi_PASS[40] = "YYYY";  // put your PASSWORD WiFi access point in the code

    Another thing to adjust is the local altitude AMSL of the circuit, the mslH constant, to 
    calculate the normalized air pressure from local to MSL; set aswell your timezone for daily rain
    calculation; do not forget to specify your Wunderground weather station ID and PASSWORD, if activated by
    the constant "isWUNDERactive=true"; of course you have to insert your APRS data access if activated by
    the constant "isAPRSactive=true"; if you are not interested in the Wunderground or the APRS you have
    just to put the respective value to "false" and avoid to set other respective values (ID, PASS, callsign, pass, etc.);
    
    due to not precise values of temperature and humidity of my BME280 board I introduced two offset values
    maybe you want to personalize aswell:
    
    const float mslH=285;  // local altitude AMSL (m) where the circuit is
    const long utcOffset = +3600;  // timezone for local time in seconds (+3600" = +1h)
    char mywunderID[40] = "IDIDID";  // your Wunderground weather station ID
    char mywunderPASS[40] = "PsWPswP";  // your Wunderground weather station password
    const double bmeTempOffset=-3.4;  // BME280 offset internal temperature in C
    const double bmeHumiOffset=+12.0;  // BME280 offset internal humidity 
    const char myAPRScallsign[40] = "CALLSIGN-13"; // your ham radio callsign, user
    const char myAPRSpasscode[40] = "12345"; // your ham radio passcode, pass
    const char myAPRSlatLon[40] = "4018.23N/01435.16E"; // your weather Station Position DDMM.MMy/DDDMM.MMx
    const char APRSserver[40] = "rotate.aprs2.net";  // APRS url server

    
 - this sketch is derived from the decoding example code made by Matthias Prinke (read copyright below);
    I used the BresserWeatherSensorReceiver library ver. 0.36.3;
    before compiling you have to personalize WeatherSensorCfg.h as specified by the author; I modified
    the following line numbers commenting/uncommenting as necessary; very important is the line number 93 where you could
    enter your station ID if you have more than one around, if you leave it empty you will receive any station ID, but
    if you ENTER IT PLEASE NOTE that it will change every station reset or battery change so you need to keep it
    updated manually!

      89:  #define SENSOR_IDS_EXC { }
      93:  #define SENSOR_IDS_INC { 0xD144 }
      101: //#define WIND_DATA_FIXEDPOINT 
      105: //#define BRESSER_5_IN_1
      106: //#define BRESSER_6_IN_1
      107: #define BRESSER_7_IN_1
      108: //#define BRESSER_LIGHTNING
      109: //#define BRESSER_LEAKAGE
      151: #define ARDUINO_TTGO_LoRa32_V21new

  Modifications log:
  ------------------
  23.12.2025  - APRS_windgustmph was=wu_windgustmph, now=wu_windgustmph_10m
              - APRS packet, unused field "p..." (about last 24h rain) now is not present anymore
              - appended telemetry_in_comment at the end of the APRS packet (Tn Bn Mn An Rn Wn Nn)
                regarding failures counters T=time, B=bresser, M=BME, A=APRS, R=reboots, W=wunder, N=network WiFi
  24.12.2025  - corrected APRS_raindaily100in was U.DD (U) now is UDD (U.DD * 100)
              - modified code to avoid a leading unwanted space out of String(value,0) for value <10...
              - all failure counters >9 will cause the alarm and a MCU restart by watchdog
              - print a message log before attempting to receive data from Bresser
  06.01.2026  - added options to exclude (active/not active) uploading data to WUNDER and/or APRS
              - added sensorBatteryStatus as + (ok) or - (needs change) in telemetry_in_comment
  13.01.2026  - OLED is active for 10 minutes then it switch off
              - moved wunder and aprs code inside bresser station sensor reading loop
              - moved telemetry_in_comment in aprs code
              - removed set to zero reboot counter if failures numbers too high (already present during boot)
              - added sensorBatteryStatus as + (ok) or - (needs change) display bottom right
              - added message log after daily counters reset and after set off the display
*/

//////////////////////////////////////////////////////////////////////////////////////////////////
// BresserWeatherSensorOLED.ino
//
// Example for BresserWeatherSensorReceiver
//
// This sketch prints the received weather sensor values to the on-board OLED display.
// See https://github.com/adafruit/Adafruit_SSD1306/tree/master/examples for text style options
// and scrolling.
//
// Notes:
// - Currently only some boards by LILYGO are supported.
//
// https://github.com/matthias-bs/BresserWeatherSensorReceiver
//
//
// created: 10/2025
//
//
// MIT License
//
// Copyright (c) 2025 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:
// 20251006 Created
//
///////////////////////////////////////////////////////////////////////////////////////////////////

#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "WeatherSensorCfg.h"
#include "WeatherSensor.h"
#include <WiFi.h>
#include <NTPClient.h>
#include  <Adafruit_BME280.h>
#include "TimeLib.h"
#include <esp_task_wdt.h>
#include <Preferences.h>
#include <rom/rtc.h>

const boolean isDebug = true;   // set to "true" to activate debug on serial monitor
                                // if "true" the serial monitor MUST be available or
                                // the sketch does not run;

//*************************//personalize here//********************************
const unsigned long OLED_time_off = (10 * 60 * 1000); // 10' minutes to switch off display
//*********** WIFI
const char WiFi_SSID[40] = "APNAME";  // put your SSID WiFi access point here
const char WiFi_PASS[40] = "APPASSWORD";  // put your PASSWORD WiFi access point here
const byte maxCONN_attempts = 8;  // nr. of WiFi connection attempts

//*********** NTP
const char poolUrl[] = "it.pool.ntp.org";  // NTP url server
const long utcOffset = +3600;  // timezone for local time in seconds (+3600" = +1h)
const unsigned long updateNTPRate = (180 * (60 * 1000)); // 180 minutes for NTP update
const byte maxTIME_attempts = 4;  // nr. of NTP update attempts

//*********** WUNDERGROUND
const boolean isWUNDERactive=false;
const char mywunderID[40] = "IDIDID";  // your weather station ID
const char mywunderPASS[40] = "PASSPASS";  // your weather station password
const unsigned long wunderUpdateRate = (7 * ((60) * 1000));  // 7 minutes for Wundeground update

//*********** APRS
const boolean isAPRSactive=false;
const char myAPRScallsign[40] = "CALLSIGN-13"; // your ham radio callsign, user
const char myAPRSpasscode[40] = "123456"; // your ham radio passcode, pass
const char myAPRSlatLon[40] = "4512.83N/011369.26E"; // your weather Station Position DDMM.MMy/DDDMM.MMx
const char APRSserver[40] = "rotate.aprs2.net";  // APRS url server
const long APRSport = 14580;  // APRS server port
const unsigned long APRSUpdateRate = (11 * ((60) * 1000));  // 11 minutes for APRS update

//*********** BME
const double mslH=210;  // local altitude AMSL (m) where the circuit is, for BME280 pressure sensor calc
const double bmeTempOffset=-3.4;  // BME280 offset internal temperature in C
const double bmeHumiOffset=+12.0;  // BME280 offset internal humidity
//*************************//----------------//********************************

double altitudeft=0;
double Altitude = 0;
double PressurehPa = 0;
double mslP = 0;
double PressurehPaMSL = 0;
double Pressurein = 0;
double PressureinMSL = 0;
double InternalTemperature = 0;
double InternalHumidity = 0;
double initialRain_mm = 0;
double rainLastRead_mm = 0;
double rainLastRead_in = 0;
double rainPreviousReads_mm = 0;
double rainTotalHH_mm = 0;
double rainTotalHH_in = 0;
double rainTotalToday_mm = 0;
double rainTotalToday_in = 0;
double windSpeedkmh = 0;
double windGustkmh = 0;
double min2upd=0;
double dpNC=0;
double dewptC=0;
double dpA=0;
double dpB=0;
double dpC=0;
double calcElaps=0;
byte w02s=0;
byte w02d=0;
byte w10g=0;
byte wunderCount=0;
byte cMM=0;
double wind02speedmph[3]={0,0,0};
double wind02dir[3]={0,0,0};
double wind10gustmph[11]={0,0,0,0,0,0,0,0,0,0,0};
double rainLastHH_mm[60]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
boolean isTimeUpdated = false;
boolean isDailyRainResetted = false;
boolean isTooFailures = false;
boolean isOLEDoff=false;
unsigned long prevNTPMillis = 0;
unsigned long actualNTPMillis = 0;
unsigned int ret = 0;
unsigned long prevSensorMillis = 0;
unsigned long actualSensorMillis = 0;
unsigned long countWindreads = 0;
unsigned long countRainreads = 0;
unsigned long prevOLEDMillis = 0;
unsigned long actualOLEDMillis = 0;
const byte buzzerPin=12;
const byte ledPin=25;
const unsigned long updateSensorRate = (60 * 1000); // 60", Sensors update rate
const double mslL=-0.00065;  // standard temperature lapse rate (K/m)
const double mslT=288.15;  // standard temperature at sea level (K) [15C] 
const double mslG=9.80665; // standard acceleration due to gravity (m/s2)
const double mslR=287.05; // specific gas constant for air (J/(kg*K))
unsigned long prevWundMillis = 0;
unsigned long actualWundMillis = 0;
unsigned long actualAPRSMillis = 0;
unsigned long prevAPRSMillis = 0;
long failures_NTP = 0;
long failures_wunder = 0;
long failures_bresser = 0;
long failures_WIFI = 0;
long failures_BME280 = 0;
long failures_APRS = 0;
long calcRes=0;
String elaps="";
String netResponse="";
String telemetry_in_comment="";
String trimmed="";
int netRsize=640;
int sensorBatteryStatus=0;

time_t epoch = 0;
time_t epochUTC = 0;
WiFiClient client;
Preferences preferences;

double wu_tempf=0;
double wu_humidity=0;
double wu_windspeedmph=0;
double wu_windgustmph=0;
double wu_winddir=0;
double wu_solarradiationwm2=0;
double wu_rainin=0;
double wu_dailyrainin=0;
double wu_UV=0;
double wu_baromin=0;
double wu_indoortempf=0;
double wu_indoorhumidity=0;
double wu_dewptf=0;
double wu_windspdmph_avg2m=0;
double wu_winddir_avg2m=0;
double wu_windgustmph_10m=0;
String wuPacket="";
char wuserver[]="weatherstation.wunderground.com";  // wunderground url

boolean bresser_tempf_ok=false;
boolean bresser_humidity_ok=false;
boolean bresser_wind_ok=false;
boolean bresser_solarradiationwm2_ok=false;
boolean bresser_rainin_ok=false;
boolean bresser_UV_ok=false;
boolean bresser_baromin_ok=false;
boolean bresser_indoortempf_ok=false;
boolean bresser_indoorhumidity_ok=false;
boolean bresser_dewptf_ok=false;

long APRS_winddir=0;
long APRS_windspeedmph=0;
long APRS_windgustmph=0;
long APRS_tempfpos=0;
boolean isAPRS_tempf_negative=false;
long APRS_rain100in=0;
long APRS_raindaily100in=0;
long APRS_barom10hpa=0;
long APRS_humidity=0;
long APRS_day=0;
long APRS_hour=0;
long APRS_minute=0;
long APRS_UV=0;
long APRS_solarradiationwm2=0;
String APRSPacket="";
String APRSlogin = "user " + String(myAPRScallsign) + " pass " + String(myAPRSpasscode) + " vers ArduinoWX 1.0\n";
unsigned int reboot_count=0;

#define WDT_TIMEOUT 60000  // watchdog 60", in millis
#define MAX_SENSORS 1
#define RX_TIMEOUT 180000 // sensor receive timeout [ms]
#define RX_FLAGS (DATA_COMPLETE | DATA_ALL_SLOTS)
#define OLED_RESET -1
#define SCREEN_WIDTH 128    // OLED display width, in pixels
#define SCREEN_HEIGHT 32    // OLED display height, in pixels
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, poolUrl, utcOffset);

WeatherSensor weatherSensor;
Adafruit_BME280 bme;
    
void setup() {
    wuPacket.reserve(640);
    APRSPacket.reserve(640);
    netResponse.reserve(netRsize);
    elaps.reserve(4);
    trimmed.reserve(6);
    telemetry_in_comment.reserve(128);
    if (isDebug) {  // Serial port for debugging purposes
      Serial.begin(115200);
      delay(4000);
      while (!Serial) {}
    }
    if (isDebug == true) {Serial.println();}
    if (isDebug == true) {Serial.println(F("------------------------------------------------"));}
    if (isDebug == true) {Serial.println(F("-------------------STARTING---------------------"));}
    if (isDebug == true) {Serial.println(F("------------------------------------------------"));}
    if (isDebug == true) {Serial.println(F("* serial ok *"));}
    ret=bme.begin(0x76, &Wire);  // default address=0x77
    if (ret){
      bme.setSampling(Adafruit_BME280::MODE_NORMAL,     /* Operating Mode: SLEEP FORCED NORMAL */
                      Adafruit_BME280::SAMPLING_X16,    /* Temperature oversampling: NONE X1 X2 X4 X8 X16 */
                      Adafruit_BME280::SAMPLING_X16,    /* Pressure oversampling: NONE X1 X2 X4 X8 X16 */
                      Adafruit_BME280::SAMPLING_X16,    /* Humidity oversampling: NONE X1 X2 X4 X8 X16 */
                      Adafruit_BME280::FILTER_X16,      /* Filtering: OFF X2 X4 X8 X16 */
                      Adafruit_BME280::STANDBY_MS_10);  /* Standby time: 0_5 10 20 62_5 125 250 500 1000 */
      if (isDebug == true) {Serial.println(F("* BME280 ok *"));}
     }else{
      if (isDebug == true) {Serial.println(F("* BME280 not found! *"));}
      failures_BME280++;
    }
    pinMode(buzzerPin, OUTPUT);
    pinMode(ledPin, OUTPUT);

    // I2C pin configuration
    Wire.begin(OLED_SDA, OLED_SCL);
    
    // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
    if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
        log_e("SSD1306 allocation failed");
    }

    // WATCHDOG
    esp_task_wdt_config_t twdt_config = {
        .timeout_ms = WDT_TIMEOUT,
        .idle_core_mask = (1 << portNUM_PROCESSORS) - 1,    // Bitmask of all cores
        .trigger_panic = true,
    };
    esp_task_wdt_deinit(); // wdt is enabled by default, so we need to deinit it first
    esp_task_wdt_init(&twdt_config); // panic enabled so ESP32 restarts
    esp_task_wdt_add(NULL); // add current thread to WDT watch
    if (isDebug) {Serial.println(F("* Watchdog active *"));}
    
    preferences.begin("reboot", false);  // reboot counter and why, false means r/w
      reboot_count = preferences.getUInt("count", 0);
      RESET_REASON reason = rtc_get_reset_reason(0); // Core 0
      if (reason != POWERON_RESET) {
        if (isDebug) {Serial.println(F("* ALERT: Last reset caused by watchdog or unusual reason! *"));}
        switch (reason) {
          case 1:  if (isDebug) {Serial.println(F("POWERON_RESET, 1, Vbat power on reset")); break;}
          case 3:  if (isDebug) {Serial.println(F("SW_RESET, 3, Software reset")); break;}
          case 4:  if (isDebug) {Serial.println(F("OWDT_RESET, 4, Legacy watch dog reset")); break;}
          case 5:  if (isDebug) {Serial.println(F("DEEPSLEEP_RESET, 5, Deep Sleep reset")); break;}
          case 6:  if (isDebug) {Serial.println(F("SDIO_RESET, 6, Reset by SLC module")); break;}
          case 7:  if (isDebug) {Serial.println(F("TG0WDT_SYS_RESET, 7, Timer Group0 Watch dog reset")); break;}
          case 8:  if (isDebug) {Serial.println(F("TG1WDT_SYS_RESET, 8, Timer Group1 Watch dog reset")); break;}
          case 9:  if (isDebug) {Serial.println(F("RTCWDT_SYS_RESET, 9, RTC Watch dog reset")); break;}
          case 10: if (isDebug) {Serial.println(F("INTRUSION_RESET, 10, Instrusion tested to reset CPU")); break;}
          case 11: if (isDebug) {Serial.println(F("TGWDT_CPU_RESET, 11, Time Group reset CPU")); break;}
          case 12: if (isDebug) {Serial.println(F("SW_CPU_RESET, 12, Software reset CPU")); break;}
          case 13: if (isDebug) {Serial.println(F("RTCWDT_CPU_RESET, 13, RTC Watch dog Reset CPU")); break;}
          case 14: if (isDebug) {Serial.println(F("EXT_CPU_RESET, 14, for APP CPU, reset by PRO CPU")); break;}
          case 15: if (isDebug) {Serial.println(F("RTCWDT_BROWN_OUT_RESET, 15, Reset when the vdd voltage is not stable")); break;}
          case 16: if (isDebug) {Serial.println(F("RTCWDT_RTC_RESET, 16, RTC Watch dog reset digital core and rtc module")); break;}
          default: if (isDebug) {Serial.println(F("NO_MEAN, unknown reason")); break;}
        }
        reboot_count++;
      preferences.putUInt("count", reboot_count);
      }    
    preferences.end();
    if (isDebug) {Serial.print(F("Actual watchdog/unusual reboot counter = "));}
    if (isDebug) {Serial.println(reboot_count);}
    
    display.clearDisplay();
    display.setTextColor(SSD1306_WHITE); // Draw white text
    display.setCursor(0,0);              // Start at top-left corner
    display.cp437(true);                 // Use full 256 char 'Code Page 437' font
    display.println(F("   Bresser Weather  "));
    display.println(F("   + BME sensors RX "));
    display.println(F(" Wunderground/APRS TX"));
    display.println(F("    868Mhz + WiFi    "));
    display.display(); // Show initial text
    tone (buzzerPin,1000,(1*1000));  // Hz, m/sec
    delay(6000);
    weatherSensor.begin();
    weatherSensor.setSensorsCfg(MAX_SENSORS, RX_FLAGS);

    setTime(967680000);  // initial datetime: 31/08/2000 00:00:00 in epoch format
    if (strcmp(WiFi_SSID,"") != 0) {  // update NTP time
      connectWiFi();
      TimeNTPUpdate();
      WiFidisconnect();
     } else {
      if (isDebug) {Serial.println(F("Empty SSID, no WiFi, noTimeSet!"));}
    }
    if (isTimeUpdated==false) {
      display.clearDisplay();
      display.setCursor(0,0);
      display.println(F("   Not possible to   "));
      display.println(F("  get initial Time   "));
      display.println(F("      via WiFi!!     "));
      display.println(F("    ** STOPPED **    "));
      display.display();
      while(true) {  // stop running, not possible to continue without actual time, MCU will restart by watchdog
        display.invertDisplay(true);
        tone (buzzerPin,800,(1*1000));  // Hz, m/sec
        delay(1000);
        display.invertDisplay(false);
        tone (buzzerPin,1100,(1*1000));  // Hz, m/sec
        delay(1000);  
      }
    }
}//setup()

void loop() {
    //---------------  daily counters reset at 00:00 l.t.
    if (((hour() == 0) && (minute() == 0)) && (isDailyRainResetted == false)){
      rainTotalToday_mm=0;
      failures_NTP = 0;
      failures_wunder = 0;
      failures_bresser = 0;
      failures_WIFI = 0;
      failures_BME280 = 0;
      failures_APRS = 0;
      if (reboot_count != 0) {
        preferences.begin("reboot", false);
         reboot_count = 0;
         preferences.putUInt("count", reboot_count);
        preferences.end();
      }            
      isDailyRainResetted=true;
      if (isDebug) {Serial.println(F("Daily counters reset done."));}
    }
    if (((hour() == 0) && (minute() != 0)) && (isDailyRainResetted == true)){  // prepare for next reset
      isDailyRainResetted=false;
    }

    //--------------- time to switch off OLED
    actualOLEDMillis=millis();
    if (prevOLEDMillis > actualOLEDMillis) {  // manage millis() rollover
      prevOLEDMillis=actualOLEDMillis;
      actualOLEDMillis=prevOLEDMillis + OLED_time_off;
    }
    if (((prevOLEDMillis + OLED_time_off) <= actualOLEDMillis) && (isOLEDoff==false)) {
      display.ssd1306_command(SSD1306_DISPLAYOFF);
      isOLEDoff=true;
      if (isDebug) {Serial.println(F("OLED timeout, set it OFF."));}
      prevOLEDMillis=millis();
    }
    
    actualSensorMillis=millis();
    if (prevSensorMillis > actualSensorMillis) {  // manage millis() rollover
      prevSensorMillis=actualSensorMillis;
      actualSensorMillis=prevSensorMillis + updateSensorRate;
    }
    //*********************************************************************************************** Bresser
    if (((prevSensorMillis + updateSensorRate) <= actualSensorMillis) || prevSensorMillis==0) {
      weatherSensor.clearSlots();
      if (isDebug) {Serial.println(F("Attempt to receive data from Bresser sensors until RX_TIMEOUT"));}
      #if (CORE_DEBUG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO)
          bool decode_ok = weatherSensor.getData(RX_TIMEOUT, RX_FLAGS, 0, nullptr);
       #else
          weatherSensor.getData(RX_TIMEOUT, RX_FLAGS, 0, nullptr);
      #endif
      log_i("decode_ok: %d", decode_ok);
      if (isDebug) {printTime();}
      cMM=minute();
      epochUTC = (now() - utcOffset);
      APRS_day=day(epochUTC);
      APRS_hour=hour(epochUTC);
      APRS_minute=minute(epochUTC);
      for (size_t i = 0; i < weatherSensor.sensor.size(); i++) {
        if (!weatherSensor.sensor[i].valid) continue;
        if ((weatherSensor.sensor[i].s_type == SENSOR_TYPE_WEATHER0) || (weatherSensor.sensor[i].s_type == SENSOR_TYPE_WEATHER1)) {
              //----------------------------------------------------------------- read external sensors via radio 868Mhz
              if (isDebug) {Serial.print(F("Bresser weather sensor actual ID="));}
              if (isDebug) {Serial.println(weatherSensor.sensor[i].sensor_id,HEX);}
              sensorBatteryStatus=weatherSensor.sensor[i].battery_ok;
              if ((isDebug) && (sensorBatteryStatus == 1)) {Serial.println(F("Bresser battery OK"));}
              if ((isDebug) && (sensorBatteryStatus == 0)) {Serial.println(F("** Bresser battery LOW! **"));}
              if (weatherSensor.sensor[i].w.temp_ok) {  // wunderground "tempf"
                  bresser_tempf_ok=true;
                  if (isDebug == true) {Serial.print(F("Temperature C = "));}
                  if (isDebug == true) {Serial.print(weatherSensor.sensor[i].w.temp_c,1);}
                  wu_tempf=(weatherSensor.sensor[i].w.temp_c * 9 / 5) + 32;
                  wu_tempf=Round1Dec(wu_tempf);
                  APRS_tempfpos=Round0Dec(wu_tempf);
                  if (APRS_tempfpos < 0){
                    isAPRS_tempf_negative=true;
                    APRS_tempfpos=(APRS_tempfpos * -1);
                   }else{
                    isAPRS_tempf_negative=false;
                  }
                  if (isDebug == true) {Serial.print(F(", F = "));}
                  if (isDebug == true) {Serial.println(wu_tempf,1);}
               }else{
                  bresser_tempf_ok=false;
                  if (isDebug == true) {Serial.println(F("* failed to read Bresser tempf, value not set *"));}
                  failures_bresser++;
              }
              if (weatherSensor.sensor[i].w.humidity_ok) {  // wunderground "humidity"
                  bresser_humidity_ok=true;
                  if (isDebug == true) {Serial.print(F("Humidity % = "));}
                  if (isDebug == true) {Serial.print(weatherSensor.sensor[i].w.humidity,1);}
                  wu_humidity=weatherSensor.sensor[i].w.humidity;
                  wu_humidity=Round0Dec(wu_humidity);
                  APRS_humidity=wu_humidity;
                  if (isDebug == true) {Serial.print(F(" = "));}
                  if (isDebug == true) {Serial.println(wu_humidity,0);}
               }else{
                  bresser_humidity_ok=false;
                  if (isDebug == true) {Serial.println(F("* failed to read Bresser humidity, value not set *"));}
                  failures_bresser++;
              }
              if ((weatherSensor.sensor[i].w.temp_ok) && (weatherSensor.sensor[i].w.humidity_ok)) {  // wunderground dewptf
                  bresser_dewptf_ok=true;
                  dpA=(weatherSensor.sensor[i].w.humidity / 100.0F);
                  dpB=(17.27 * weatherSensor.sensor[i].w.temp_c);
                  dpC=(237.3 + weatherSensor.sensor[i].w.temp_c);
                  dpNC=(log(dpA) + (dpB / dpC)) / 17.27;
                  dewptC=(237.3 * dpNC) / (1 - dpNC);
                  wu_dewptf=(dewptC * 9 / 5) + 32;
                  wu_dewptf=Round1Dec(wu_dewptf);
                  if (isDebug == true) {Serial.print(F("Dew Point C = "));}
                  if (isDebug == true) {Serial.print(dewptC,1);}
                  if (isDebug == true) {Serial.print(F(", F = "));}
                  if (isDebug == true) {Serial.println(wu_dewptf,1);}
               }else{
                  bresser_dewptf_ok=false;
                  if (isDebug == true) {Serial.println(F("* failed to calculate Bresser dewptf, value not set *"));}
                  failures_bresser++;
              }
              if (weatherSensor.sensor[i].w.wind_ok) {  // wunderground/APRS "windspeedmph", "windgustmph", "winddir"
                  bresser_wind_ok=true;
                  countWindreads++;
                  if (isDebug == true) {Serial.print(F("Wind counter = "));}
                  if (isDebug == true) {Serial.println(countWindreads);}
                  windSpeedkmh=(weatherSensor.sensor[i].w.wind_avg_meter_sec * 3.6);
                  windSpeedkmh=Round1Dec(windSpeedkmh);
                  if (isDebug == true) {Serial.print(F("Wind km/h = "));}
                  if (isDebug == true) {Serial.print(windSpeedkmh,1);}
                  if (isDebug == true) {Serial.print(F(", m/s = "));}
                  if (isDebug == true) {Serial.print(weatherSensor.sensor[i].w.wind_avg_meter_sec,1);}
                  wu_windspeedmph=(weatherSensor.sensor[i].w.wind_avg_meter_sec * 2.237);
                  wu_windspeedmph=Round1Dec(wu_windspeedmph);
                  APRS_windspeedmph=Round0Dec(wu_windspeedmph);
                  if (isDebug == true) {Serial.print(F(", mph = "));}
                  if (isDebug == true) {Serial.print(wu_windspeedmph,1);}
                  
                  w02s=(wind02speedmph[0] + 1);  // average speed mph last 2 minutes
                  if (w02s>2) {w02s=1;}
                  wind02speedmph[w02s]=wu_windspeedmph;
                  wind02speedmph[0]=w02s;
                  wu_windspdmph_avg2m=0;
                  for (byte c=1;c<=2;c++){
                    wu_windspdmph_avg2m = (wu_windspdmph_avg2m + wind02speedmph[c]);
                  }
                  if (countWindreads > 1) {
                    wu_windspdmph_avg2m = (wu_windspdmph_avg2m / 2.0F);
                   }else{
                    wu_windspdmph_avg2m = (wu_windspdmph_avg2m / 1.0F);
                  }
                  wu_windspdmph_avg2m=Round1Dec(wu_windspdmph_avg2m);
                  if (isDebug == true) {Serial.print(F(", avg last 2' mph = "));}
                  if (isDebug == true) {Serial.println(wu_windspdmph_avg2m,1);}
  
                  windGustkmh=(weatherSensor.sensor[i].w.wind_gust_meter_sec * 3.6);
                  windGustkmh=Round1Dec(windGustkmh);
                  if (isDebug == true) {Serial.print(F("Wind gust km/h = "));}
                  if (isDebug == true) {Serial.print(windGustkmh,1);}
                  if (isDebug == true) {Serial.print(F(", gust m/s = "));}
                  if (isDebug == true) {Serial.print(weatherSensor.sensor[i].w.wind_gust_meter_sec,1);}
                  wu_windgustmph=(weatherSensor.sensor[i].w.wind_gust_meter_sec * 2.237);
                  wu_windgustmph=Round1Dec(wu_windgustmph);
                  if (isDebug == true) {Serial.print(F(", gust mph = "));}
                  if (isDebug == true) {Serial.print(wu_windgustmph,1);}
                  w10g=(wind10gustmph[0] + 1);  // top gust mph last 10 minutes
                  if (w10g>10) {w10g=1;}
                  wind10gustmph[w10g]=wu_windgustmph;
                  wind10gustmph[0]=w10g;
                  wu_windgustmph_10m=0;
                  for (byte c=1;c<=10;c++){
                    if (wind10gustmph[c] > wu_windgustmph_10m) {wu_windgustmph_10m = wind10gustmph[c];}
                  }
                  wu_windgustmph_10m=Round1Dec(wu_windgustmph_10m);
                  APRS_windgustmph=Round0Dec(wu_windgustmph_10m);
                  if (isDebug == true) {Serial.print(F(", last 10' gust mph = "));}
                  if (isDebug == true) {Serial.println(wu_windgustmph_10m,1);}
  
                  if (isDebug == true) {Serial.print(F("Wind Direction deg = "));}
                  if (isDebug == true) {Serial.print(weatherSensor.sensor[i].w.wind_direction_deg,0);}
                  wu_winddir=weatherSensor.sensor[i].w.wind_direction_deg;
                  wu_winddir=Round0Dec(wu_winddir);
                  APRS_winddir=wu_winddir;
                  if (isDebug == true) {Serial.print(F(" = "));}
                  if (isDebug == true) {Serial.print(wu_winddir,0);}
                         
                  w02d=(wind02dir[0] + 1);  // calc average dir last 2 minutes
                  if (w02d>2) {w02d=1;}
                  wind02dir[w02d]=wu_winddir;
                  wind02dir[0]=w02d;
                  if (countWindreads > 1){  // two values to average
                    double rad1=(wind02dir[1] * (PI / 180)); 
                    double rad2=(wind02dir[2] * (PI / 180));
                    double sumX=(sin(rad1) + sin(rad2));
                    double sumY=(cos(rad1) + cos(rad2));
                    double radResult=(atan2(sumX, sumY));
                    wu_winddir_avg2m=(radResult * (180 / PI));
                    if (wu_winddir_avg2m == 360) {wu_winddir_avg2m = 0;}
                    if (wu_winddir_avg2m < 0) {wu_winddir_avg2m += 360;}
                   }else{  // just one value, the first
                    wu_winddir_avg2m = wind02dir[1];
                  }
                  wu_winddir_avg2m=Round0Dec(wu_winddir_avg2m);
                  if (wu_winddir_avg2m == 0) {wu_winddir_avg2m=360;}  // I do not want 0 as direction, so 360 instead...
                  if (isDebug == true) {Serial.print(F(", avg last 2' dir deg = "));}
                  if (isDebug == true) {Serial.println(wu_winddir_avg2m,0);}
               }else{
                  bresser_wind_ok=false;
                  if (isDebug == true) {Serial.println(F("* failed to read Bresser wind, values speed/gust/dir not set *"));}
                  failures_bresser++;
              }
              if (weatherSensor.sensor[i].w.light_ok) {  // wunderground "solarradiation" in W/m2
                  bresser_solarradiationwm2_ok=true;
                  if (isDebug == true) {Serial.print(F("Light klx = "));}
                  if (isDebug == true) {Serial.print(weatherSensor.sensor[i].w.light_klx,2);}
                  wu_solarradiationwm2=(weatherSensor.sensor[i].w.light_klx * 7.9 );
                  wu_solarradiationwm2=Round2Dec(wu_solarradiationwm2);
                  APRS_solarradiationwm2=Round0Dec(wu_solarradiationwm2);
                  if (isDebug == true) {Serial.print(F(", Light W/m2 = "));}
                  if (isDebug == true) {Serial.println(wu_solarradiationwm2,2);}
               }else{
                  bresser_solarradiationwm2_ok=false;
                  if (isDebug == true) {Serial.println(F("* failed to read Bresser solarradiationwm2, value not set *"));}
                  failures_bresser++;
              }
  
              if (weatherSensor.sensor[i].w.rain_ok) {  // wunderground "rainin"
                  bresser_rainin_ok=true;
                  countRainreads++;
                  if (isDebug == true) {Serial.print(F("Rain counter = "));}
                  if (isDebug == true) {Serial.print(countRainreads);}
                  if ((countRainreads==1) || (initialRain_mm > weatherSensor.sensor[i].w.rain_mm)) {  // initial or rollover
                    initialRain_mm = weatherSensor.sensor[i].w.rain_mm;
                    rainPreviousReads_mm = 0;
                  }
                  if (isDebug == true) {Serial.print(F(", sensor = "));}
                  if (isDebug == true) {Serial.print(weatherSensor.sensor[i].w.rain_mm,2);}
                  if (isDebug == true) {Serial.print(F(", initial = "));}
                  if (isDebug == true) {Serial.print(initialRain_mm,2);}
                  rainLastRead_mm=(weatherSensor.sensor[i].w.rain_mm - initialRain_mm - rainPreviousReads_mm);
                  if (isDebug == true) {Serial.print(F(", last = "));}
                  if (isDebug == true) {Serial.print(rainLastRead_mm,2);}
                  if (isDebug == true) {Serial.print(F(", previous = "));}
                  if (isDebug == true) {Serial.println(rainPreviousReads_mm,2);}
                  
                  if (isDebug == true) {Serial.print(F("Rain mm = "));}  // rain last minute
                  if (isDebug == true) {Serial.print(rainLastRead_mm,2);}
                  rainLastRead_in=(rainLastRead_mm / 25.4);
                  rainLastRead_in=Round2Dec(rainLastRead_in);
                  if (isDebug == true) {Serial.print(F(", in = "));}
                  if (isDebug == true) {Serial.println(rainLastRead_in,2);}
  
                  rainLastHH_mm[cMM]=rainLastRead_mm;  // rain last HH (past 60')
                  rainTotalHH_mm=0;
                  for (byte m=0;m<=59;m++){
                    rainTotalHH_mm += rainLastHH_mm[m];
                  }
                  if (isDebug == true) {Serial.print(F("Rain last Hour (last 60') mm = "));}
                  if (isDebug == true) {Serial.print(rainTotalHH_mm,2);}
                  wu_rainin=(rainTotalHH_mm / 25.4);
                  wu_rainin=Round2Dec(wu_rainin);
                  APRS_rain100in=(wu_rainin * 100);
                  if (isDebug == true) {Serial.print(F(", in = "));}
                  if (isDebug == true) {Serial.println(wu_rainin,2);}
                  if (isDebug == true) {Serial.print(F("Rain last 60' (DETAILED) mm = "));}
                  for (byte m=0;m<=59;m++){
                    if (isDebug == true) {Serial.print(rainLastHH_mm[m],2);}
                    if (isDebug == true) {Serial.print(F(" "));}
                  }
                  if (isDebug == true) {Serial.println(F(""));}
  
                  rainTotalToday_mm += rainLastRead_mm;  // rain today since 00:00 local time
                  if (isDebug == true) {Serial.print(F("Rain Today (since 00:00) mm = "));}
                  if (isDebug == true) {Serial.print(rainTotalToday_mm,2);}
                  rainTotalToday_in=(rainTotalToday_mm / 25.4);
                  rainTotalToday_in=Round2Dec(rainTotalToday_in);
                  wu_dailyrainin=rainTotalToday_in;
                  APRS_raindaily100in=(wu_dailyrainin * 100);
                  if (isDebug == true) {Serial.print(F(", in = "));}
                  if (isDebug == true) {Serial.println(wu_dailyrainin,2);}
                  rainPreviousReads_mm += rainLastRead_mm;
               }else{
                  bresser_rainin_ok=false;
                  if (isDebug == true) {Serial.println(F("* failed to read Bresser rainin, values rainin/daily not set *"));}
                  failures_bresser++;
              }
              
              if (weatherSensor.sensor[i].w.uv_ok) {  // wunderground "UV"
                  bresser_UV_ok=true;
                  if (isDebug == true) {Serial.print(F("UV Index = "));}
                  if (isDebug == true) {Serial.print(weatherSensor.sensor[i].w.uv,1);}
                  wu_UV=weatherSensor.sensor[i].w.uv;
                  wu_UV=Round1Dec(wu_UV);
                  APRS_UV=Round0Dec(wu_UV);
                  if (isDebug == true) {Serial.print(F(" = "));}
                  if (isDebug == true) {Serial.println(wu_UV,1);}
               }else{
                  bresser_UV_ok=false;
                  if (isDebug == true) {Serial.println(F("* failed to read Bresser UV, value not set *"));}
                  failures_bresser++;
              }
              //----------------------------------------------------------------- read internal BME280 sensors via I2C
              PressurehPa = (bme.readPressure()/100.0F);  // wunderground "baromin"
              if (PressurehPa >= 356.00 && PressurehPa <= 1100.00) {  // ok if lower than 8000m, higher than -700m
                  bresser_baromin_ok=true;
                  PressurehPa=Round2Dec(PressurehPa);
                  mslP=PressurehPa;
                  if (isDebug == true) {Serial.print(F("Local Pressure hPa = "));}
                  if (isDebug == true) {Serial.print(PressurehPa,2);}
                  Pressurein=(PressurehPa * 0.02953);
                  Pressurein=Round3Dec(Pressurein);
                  if (isDebug == true) {Serial.print(F(", inHg = "));}
                  if (isDebug == true) {Serial.println(Pressurein,3);}
      
                  PressurehPaMSL = mslP * pow( (1-(mslL * mslH / mslT)), ((mslG * -1) / (mslL * mslR)) );  // normalized pressure to MSL
                  PressurehPaMSL=Round2Dec(PressurehPaMSL);
                  if (isDebug == true) {Serial.print(F("Normalized Pressure hPa = "));}
                  if (isDebug == true) {Serial.print(PressurehPaMSL,2);}
                  PressureinMSL=(PressurehPaMSL * 0.02953);
                  wu_baromin=PressureinMSL;
                  wu_baromin=Round3Dec(wu_baromin);
                  APRS_barom10hpa=Round0Dec((PressurehPaMSL * 10));
                  if (isDebug == true) {Serial.print(F(", inHg = "));}
                  if (isDebug == true) {Serial.println(wu_baromin,3);}
      
                  Altitude = bme.readAltitude(PressurehPaMSL);  // calculated with normalized MSL pressure
                  Altitude=Round0Dec(Altitude);
                  if (isDebug == true) {Serial.print(F("Normalized Altitude m = "));}
                  if (isDebug == true) {Serial.print(Altitude,0);}
                  altitudeft=(Altitude * 3.28084);
                  altitudeft=Round0Dec(altitudeft);
                  if (isDebug == true) {Serial.print(F(", ft = "));}
                  if (isDebug == true) {Serial.println(altitudeft,0);}
              }else{
                  bresser_baromin_ok=false;
                  if (isDebug == true) {Serial.println(F("* failed to read Pressure, crazy values, value baromin not set *"));}
                  failures_BME280++;
              }
              
              InternalTemperature = (bme.readTemperature() + bmeTempOffset);  // wunderground "indoortempf"
              if (InternalTemperature >= -20.00 && InternalTemperature <= 50) {
                  bresser_indoortempf_ok=true;
                  if (isDebug == true) {Serial.print(F("Internal Temp C = "));}
                  if (isDebug == true) {Serial.print(InternalTemperature,1);}
                  wu_indoortempf=(InternalTemperature * 9 / 5) + 32;
                  wu_indoortempf=Round1Dec(wu_indoortempf);
                  if (isDebug == true) {Serial.print(F(", F = "));}
                  if (isDebug == true) {Serial.println(wu_indoortempf,1);}
              }else{
                  bresser_indoortempf_ok=false;
                  if (isDebug == true) {Serial.println(F("* failed to read Internal Temperature, crazy value, not set *"));}
                  failures_BME280++;
              }
              
              InternalHumidity = (bme.readHumidity() + bmeHumiOffset);  // wunderground "indoorhumidity"
              if (InternalHumidity >= 0 && InternalHumidity <= 100) {
                  bresser_indoorhumidity_ok=true;
                  if (isDebug == true) {Serial.print(F("Internal Hum % = "));}
                  if (isDebug == true) {Serial.print(InternalHumidity,0);}
                  wu_indoorhumidity=InternalHumidity;
                  wu_indoorhumidity=Round0Dec(wu_indoorhumidity);
                  if (isDebug == true) {Serial.print(F(" = "));}
                  if (isDebug == true) {Serial.println(wu_indoorhumidity,0);}
              }else{
                  bresser_indoorhumidity_ok=false;
                  if (isDebug == true) {Serial.println(F("* failed to read Internal Humidity, crazy value, not set *"));}
                  failures_BME280++;
              }
              delay(100);
              prevSensorMillis=millis();

              //----------------------------------------------------------------- uploading to Wunderground.com
              actualWundMillis=millis();
              if (prevWundMillis > actualWundMillis) {  // manage millis() rollover
                prevWundMillis=actualWundMillis;
                actualWundMillis=prevWundMillis + wunderUpdateRate;
              }
              if ((isWUNDERactive == true) && ((prevWundMillis + wunderUpdateRate) <= actualWundMillis)) {
                elaps="WUG";
                showDisplay();
                wuPacket = "GET /weatherstation/updateweatherstation.php?";
                wuPacket += "ID=";
                wuPacket += mywunderID;
                wuPacket += "&PASSWORD=";
                wuPacket += mywunderPASS;
                wuPacket += "&dateutc=now";
                if (bresser_wind_ok==true) {
                  trimmed=String(wu_winddir,0);
                  trimmed.trim();
                  wuPacket += "&winddir=" + trimmed;
                  trimmed=String(wu_winddir_avg2m,0);
                  trimmed.trim();
                  wuPacket += "&winddir_avg2m=" + trimmed;
                  wuPacket += "&windspeedmph=" + String(wu_windspeedmph,1);
                  wuPacket += "&windspdmph_avg2m=" + String(wu_windspdmph_avg2m,1);
                  wuPacket += "&windgustmph=" + String(wu_windgustmph,1);
                  wuPacket += "&windgustmph_10m=" + String(wu_windgustmph_10m,1);
                }
                if (bresser_tempf_ok==true) {wuPacket += "&tempf=" + String(wu_tempf,1);}
                if (bresser_dewptf_ok==true) {wuPacket += "&dewptf=" + String(wu_dewptf,1);}
                if (bresser_rainin_ok==true) {wuPacket += "&rainin=" + String(wu_rainin,2);}
                if (bresser_rainin_ok==true) {wuPacket += "&dailyrainin=" + String(wu_dailyrainin,2);}
                if (bresser_baromin_ok==true) {wuPacket += "&baromin=" + String(wu_baromin,3);}
                if (bresser_humidity_ok==true) {
                  trimmed=String(wu_humidity,0);
                  trimmed.trim();
                  wuPacket += "&humidity=" + trimmed;
                }
                if (bresser_solarradiationwm2_ok==true) {wuPacket += "&solarradiation=" + String(wu_solarradiationwm2,2);}
                if (bresser_UV_ok==true) {wuPacket += "&UV=" + String(wu_UV,1);}
                if (bresser_indoortempf_ok==true) {wuPacket += "&indoortempf=" + String(wu_indoortempf,1);}
                if (bresser_indoorhumidity_ok==true) {
                  trimmed=String(wu_indoorhumidity,0);
                  trimmed.trim();
                  wuPacket += "&indoorhumidity=" + trimmed;
                }
                wuPacket += "&softwaretype=ABW%20version1.0&action=updateraw";
                wuPacket += " HTTP/1.1\r\n";
                wuPacket += "Host: ";
                wuPacket += wuserver;
                wuPacket += "\r\n";
                wuPacket += "Connection: close\r\n\r\n";
                if (isDebug == true) {Serial.println(F("------------------------------------------------"));}
                if (isDebug == true) {Serial.println(F("WuPacket ============ START"));}
                if (isDebug == true) {Serial.print(F("''"));}
                if (isDebug == true) {Serial.print(wuPacket);}
                if (isDebug == true) {Serial.println(F("''"));}
                if (isDebug == true) {Serial.println(F("WuPacket ============ END"));}
                connectWiFi();
                sendWUNDERnet();
                WiFidisconnect();
                prevWundMillis=millis();
              }
              //----------------------------------------------------------------- uploading to aprs.fi
              actualAPRSMillis=millis();
              if (prevAPRSMillis > actualAPRSMillis) {  // manage millis() rollover
                prevAPRSMillis=actualAPRSMillis;
                actualAPRSMillis=prevAPRSMillis + APRSUpdateRate;
              }
              if ((isAPRSactive == true) && ((prevAPRSMillis + APRSUpdateRate) <= actualAPRSMillis)) {
                elaps="APR";
                showDisplay();

                // telemtry_in_comment
                telemetry_in_comment="";  
                telemetry_in_comment +="T";
                if (failures_NTP <= 9) {
                  telemetry_in_comment += String(failures_NTP);
                 }else{
                  telemetry_in_comment += "!";
                }
                telemetry_in_comment += " B";
                if (failures_bresser <= 9) {
                  telemetry_in_comment += String(failures_bresser);
                 }else{
                  telemetry_in_comment += "!";
                }
                telemetry_in_comment += " M";
                if (failures_BME280 <= 9) {
                  telemetry_in_comment += String(failures_BME280);
                 }else{
                  telemetry_in_comment += "!";
                }
                telemetry_in_comment += " A";
                if (failures_APRS <= 9) {
                  telemetry_in_comment += String(failures_APRS);
                 }else{
                  telemetry_in_comment += "!";
                }
                telemetry_in_comment += " R";
                if (reboot_count <= 9) {
                  telemetry_in_comment += String(reboot_count);
                 }else{
                  telemetry_in_comment += "!";
                }
                telemetry_in_comment += " W";
                if (failures_wunder <= 9) {
                  telemetry_in_comment += String(failures_wunder);
                 }else{
                  telemetry_in_comment += "!";
                }
                telemetry_in_comment += " N";
                if (failures_WIFI <= 9) {
                  telemetry_in_comment += String(failures_WIFI);
                 }else{
                  telemetry_in_comment += "!";
                }
                if (sensorBatteryStatus == 1){
                  telemetry_in_comment += " +";
                 }else{
                  telemetry_in_comment += " -";
                }

                // APRS PACKET              
                APRSPacket="";
                APRSPacket += myAPRScallsign;
                APRSPacket += ">APRS,TCPIP*:";
                APRSPacket += "@";
                if (APRS_day < 10) {APRSPacket += "0";}
                APRSPacket += String(APRS_day);
                if (APRS_hour < 10) {APRSPacket += "0";}
                APRSPacket += String(APRS_hour);
                if (APRS_minute < 10) {APRSPacket += "0";}
                APRSPacket += String(APRS_minute);
                APRSPacket += "z";
                APRSPacket += myAPRSlatLon;
                if (bresser_wind_ok == true) {
                    APRSPacket += "_";
                    if ((APRS_winddir > 9) && (APRS_winddir <100)) {APRSPacket += "0";}
                    if (APRS_winddir < 10) {APRSPacket += "00";}
                    APRSPacket += String(APRS_winddir);
                    APRSPacket += "/";
                    if ((APRS_windspeedmph > 9) && (APRS_windspeedmph <100)) {APRSPacket += "0";}
                    if (APRS_windspeedmph < 10) {APRSPacket += "00";}
                    APRSPacket += String(APRS_windspeedmph);
                    APRSPacket += "g";
                    if ((APRS_windgustmph > 9) && (APRS_windgustmph <100)) {APRSPacket += "0";}
                    if (APRS_windgustmph < 10) {APRSPacket += "00";}
                    APRSPacket += String(APRS_windgustmph);
                }else{
                    APRSPacket += "_.../...g...";
                }
                if (bresser_tempf_ok==true) {
                    APRSPacket += "t";
                    if (isAPRS_tempf_negative == true) {
                      if (APRS_tempfpos < 10) {APRSPacket += "-0";}
                      if (APRS_tempfpos > 9) {APRSPacket += "-";}
                     }else{
                      if ((APRS_tempfpos > 9) && (APRS_tempfpos <100)) {APRSPacket += "0";}
                      if (APRS_tempfpos < 10) {APRSPacket += "00";}
                    }
                    APRSPacket += String(APRS_tempfpos);
                }else{
                    APRSPacket += "t...";
                }
                if (bresser_rainin_ok==true) {
...

This file has been truncated, please download it to see its full contents.

Credits

Marco Zonca
20 projects • 54 followers
"From an early age I learned to not use pointers"

Comments