Weathersation with following components

- BME280  (Temperature,Humidity,Pressure)
- DS21B20 (Temperature)
- xxx (Ambient Light Sensor)
- Windspeed Sensor Analog voltage from -> Adafruit Industries LLC / # 1733

Using Arduino 1.8.11 and the KNX Library from Thorsten Gering
https://github.com/thorsten-gehrig/KnxTpUart

*) The Code is a messy and for now not completely tested and reviewed. But it works for my prototype. Feel free to adapt it to your needs.



 



 const String SWversion = "SW:2024.09.22/08:19_HW:20240517";
// www.rohrhofer.org
// Arduino 1.8.11
// ESP32-S3-WROOM-1-N4
// https://github.com/thorsten-gehrig/KnxTpUart

// *** define the hardware ***
// VirtualComPort UART to USB
#define RXD1 36 // KNX RXD
#define TXD1 37 // KNX TXD
//KNX-TP UART
#define RXD2 18 // KNX RXD
#define TXD2 17 // KNX TXD
// I2C BME280,BH1750
#define SDA_PIN 19  //19 - 8 // am Prototyp falsch geroutet daher hier für den Prototypen mit 19,20 anders.
#define SCL_PIN 20  //20 - 9

#define ONE_WIRE_BUS 14 // Data wire DS18B20

#define WIND_ADC 4 // Analog Pin for Windspeed measurement // HR Pin 12 ist ADC2 und mit wiFi nicht zu gebrauchen
float prev_max_wind_speed = 0.0;

#define MODE_SWITCH 1 // Startup mode switch (for WifiConfiguration)
#define LED 2 // Onboard  LED D3 green
#define LED2 3 // Onboard  LED D4 red

#define OUT1 6
#define OUT2 7

// *** AD-Wandler I2C ADS1115 ***
#include 

Adafruit_ADS1115 ads;  /* Use this for the 16-bit version */
//Adafruit_ADS1015 ads;     /* Use this for the 12-bit version */

// *** KNX ***
#include 
// KNX physical address
#define KNXaddress "1.1.134" // KNX physical device address 1.1.134
#define KNX_ListenGroupAddress_1 "15/0/0" // OUT1
#define KNX_ListenGroupAddress_2 "15/0/1" // OUT2
// Initialize the KNX TP-UART library
KnxTpUart knx(&Serial1, KNXaddress);


// *** Include the libraries for DS18B20 Temperature Sensor ***
#include 
#include 
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);

// *** Include the libraries for BH1750 Ambient Light Sensor ***
#include 
#include 

BH1750 lightMeter;

// *** Include the libraries for the BME Enviromental Sensor ***

#include 
BME280I2C bme;    // Default : forced mode, standby time = 1000 ms
                  // Oversampling = pressure ×1, temperature ×1, humidity ×1, filter off,

int ledState = LOW;  // ledState used to set the LED
unsigned long previoussamplingMillis = 0;
unsigned long previoussendingMillis = 0;
const long samplingintervall = 1000;  // interval (milliseconds)
//const long sendingintervall = 30000;  // interval (milliseconds)
long sendingintervall = 30000; // sendinginterval (milliseconds)

float sensorValue = 0.0;
float wind_speed = 0.0;

// *** Configuration Webservice ***
#include 
#include 
#include 
#include 
#include 
#define EEPROM_SIZE 512  // 512 a 16 Bytes ergibt 32 mögliche Variablen
#define MAX_HTTP_ARGUMENTS 3
const char *CONFIG_SERVER_SSID = "ESP32_CONFIG_SERVICE";
const char *CONFIG_SERVER_PASS = "";
WebServer configServer(80);
IPAddress AP_LOCAL_IP(192, 168, 123, 1);
IPAddress AP_GATEWAY_IP(192, 168, 123, 1);
IPAddress AP_NETWORK_MASK(255, 255, 255, 0);
char buffer[64];



long prev_ms = 0;

void handleRoot() {
  String values[MAX_HTTP_ARGUMENTS];
  if (configServer.arg("SEND") == "Submit") {
    for (int httpArgument = 0; httpArgument < MAX_HTTP_ARGUMENTS; httpArgument++) {
      saveToEEPROM(httpArgument, configServer.arg(String(httpArgument)));
    }//for
  }//if
  if (configServer.arg("REBOOT") == "Reboot") {
    ESP.restart();
  }//if  
  if (configServer.arg("FORMATEEPROM") == "Format EEprom") {
    clearEEPROM();
  }//if  
  for (int httpArgument = 0; httpArgument < MAX_HTTP_ARGUMENTS; httpArgument++) {
    values[httpArgument] = readFromEEPROM(httpArgument);
  }//for
  String message = "(ESP32-KNX)
WeatherStation - Configuration";
  message += SWversion + "
";
  message += "";
  message += "";
  message += "";
  message += "";
  message += "";
  message += "";
  message += "";
  message += "(0)KNX physical device address: 1.1.134  (1)Sending intervall (ms): ms  (2)KNX Group Adr.- Windspeed:(DPT 9.005)m/s   
 
 
";
  message += "";
  configServer.send(200, "text/html", message);
}


void setup() {
  Serial.begin(115200,SERIAL_8E1, RXD1, TXD1); // VirtualComPort USB
  Serial1.begin(19200, SERIAL_8E1, RXD2, TXD2); //KNX-TPUart an ESP32 PIN 16(RX), 17(TX)
  knx.uartReset();
    //  knx.addListenGroupAddress(KNX_ListenGroupAddress_1);
    //  knx.addListenGroupAddress(KNX_ListenGroupAddress_2);
    
  pinMode(LED, OUTPUT);
  digitalWrite(LED, HIGH); // Display activity
  pinMode(LED2, OUTPUT);
  pinMode(OUT1, OUTPUT);
  pinMode(OUT2, OUTPUT);
  pinMode(MODE_SWITCH, INPUT_PULLUP);  // 0 = pressed button
  //pinMode(12,INPUT);
  pinMode(WIND_ADC,INPUT);
 

  sensors.begin(); // Start up the OnWire Sensor library for DS18B20
 
  // Initialize the I2C bus (BH1750 and BME280 library doesn't do this automatically)
  Wire.begin(SDA_PIN,SCL_PIN );
  lightMeter.begin();

while(!bme.begin())
  {
    Serial.println("[BME280] Could not find BME280 sensor!");
    delay(1000);
    break;
  }

  switch(bme.chipModel())
  {
     case BME280::ChipModel_BME280:
       Serial.println("[BME280] Found BME280 sensor! Success.");
       break;
     case BME280::ChipModel_BMP280:
       Serial.println("[BMP280] Found BMP280 sensor! No Humidity available.");
       break;
     default:
       Serial.println("[BMx280] I2C Error! No sensor?");
  }

  // *** AD-Wandler I2C ADS1115 ***
  if (!ads.begin()) {
    Serial.println("Failed to initialize ADS.");
    delay(1000);
    // while (1);
  }

 
 
//*** config service ***
  EEPROM.begin(EEPROM_SIZE);
  // clearEEPROM(); //
  if (!digitalRead(MODE_SWITCH)) {
    Serial.println("... start Wifi Setup");
    Serial.print(" please connect to -> ");
    Serial.println (AP_LOCAL_IP);
    
    WiFi.softAPConfig(AP_LOCAL_IP, AP_GATEWAY_IP, AP_NETWORK_MASK);
    WiFi.softAP(CONFIG_SERVER_SSID, CONFIG_SERVER_PASS);
    configServer.on("/", handleRoot);
    configServer.begin();
    while (true) {
      yield();
      configServer.handleClient();
    }//while
  }//if
  char buffer_physicalKNXaddress[16];
  readFromEEPROM(0).toCharArray(buffer_physicalKNXaddress, 16);
  char *EE_physicalKNXaddress = buffer;
  char buffer_sendingintervall[16];
  readFromEEPROM(1).toCharArray(buffer_sendingintervall, 16);
  char *EE_sendingintervall = buffer;
  Serial.print("KNX physical device address: "); Serial.println(EE_physicalKNXaddress);
  Serial.print("Sending intervall (ms): "); Serial.println(EE_sendingintervall);
 
  delay(2000);
  Serial.print("(0)KNX physical device address: "); Serial.println(readFromEEPROM(0));
 
  Serial.print("(1)Sending intervall (ms): "); Serial.println(readFromEEPROM(1));
  sendingintervall = readFromEEPROM(1).toInt();
  Serial.print("Setting3: "); Serial.println(readFromEEPROM(2));
 
  Serial.println(SWversion);

 
}

void loop() {
  //int16_t adc0;
  //Serial.println(digitalRead(MODE_SWITCH));
    if (!digitalRead(MODE_SWITCH)) {
            Serial.println("... start Wifi Setup");
            Serial.print(" please connect to -> ");
            Serial.println (AP_LOCAL_IP);
    
            WiFi.softAPConfig(AP_LOCAL_IP, AP_GATEWAY_IP, AP_NETWORK_MASK);
            WiFi.softAP(CONFIG_SERVER_SSID, CONFIG_SERVER_PASS);
            configServer.on("/", handleRoot);
            configServer.begin();
              while (true) {
                  yield();
                  configServer.handleClient();
                 }//while
           }//if

  unsigned long currentMillis = millis();

  // Display some activity
  if (currentMillis - previoussamplingMillis >= samplingintervall) {
    // save the last time
    previoussamplingMillis = currentMillis;

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }

         // Windspeed
        sensorValue = ads.readADC_SingleEnded(0);
        sensorValue = sensorValue - 14.0 ; // ADC Offset
  
        float voltage = ads.computeVolts(sensorValue);
        wind_speed = mapfloat(voltage, 0.41, 2, 0, 32.4); // wind speed in m/s
       
        Serial.print((float)sensorValue);
        Serial.print("-");

        Serial.print((float)voltage,4);
        Serial.print("V-");
       
        Serial.print((float)wind_speed,4);
        Serial.print("ms-");
       
        if (wind_speed > prev_max_wind_speed) {
          prev_max_wind_speed = (float)wind_speed;
           }
        Serial.println((float)prev_max_wind_speed);

  }

   // set the LED with the ledState of the variable:
   digitalWrite(LED, ledState);

    


  // *********************************************
   if (currentMillis - previoussendingMillis >= sendingintervall) {
    // save the last time
    previoussendingMillis = currentMillis;

    digitalWrite(LED2, HIGH); // Display some sending activity
    digitalWrite(LED, LOW);
    
        Serial.print("Requesting sensor values...");
        sensors.requestTemperatures(); // Send the command to get temperatures
        Serial.println("DONE");
        // After we got the temperatures, we can print them here.
        // We use the function ByIndex, and as an example get the temperature from the first sensor only.
        float tempC = sensors.getTempCByIndex(0);

        // Check if reading was successful
        if (tempC != DEVICE_DISCONNECTED_C)
          {
          Serial.print("Temp: ");
          Serial.print(tempC);
          Serial.print("°C");
          }
        else
        {
        Serial.println("[DS18B20] Error: Could not read temperature data");
        }

        float lux = lightMeter.readLightLevel();
        Serial.print("\tLight: ");
        Serial.print(lux);
        Serial.print("lx");


        float temp(NAN), hum(NAN), pres(NAN);

        BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
        BME280::PresUnit presUnit(BME280::PresUnit_Pa);
        bme.read(pres, temp, hum, tempUnit, presUnit);



        Serial.print("\tTemp: ");
        Serial.print(temp);
        Serial.print("°"+ String(tempUnit == BME280::TempUnit_Celsius ? 'C' :'F'));
        Serial.print("\tHumidity: ");
        Serial.print(hum);
        Serial.print("% RH");
        Serial.print("\tPressure: ");
        Serial.print(pres);
        Serial.print("Pa");
        Serial.print("\tWindspd.: ");
        //Serial.print(wind_speed);
        Serial.print((float)prev_max_wind_speed);
        Serial.println("m/s");
   


// Write to KNX ---------------  
        bool success = false;
        success = knx.groupWriteBool("15/0/0", true); // Heartbeatsignal /Schreibt ein true auf die Gruppenadresse
        Serial.println("Sent KNX Telegramm to 15/0/0 --> success ")+ (bool)success ;
        success = knx.groupWrite2ByteFloat("15/0/1", tempC);
        Serial.println("Sent KNX Telegramm to 15/0/1 --> success ")+ success ;
        success = knx.groupWrite2ByteFloat("15/0/3", lux);
        Serial.println("Sent KNX Telegramm to 15/0/3 --> success ")+ success;
        success = knx.groupWrite2ByteFloat("15/0/4", temp);
        Serial.println("Sent KNX Telegramm to 15/0/4 --> success ")+ success;
        success = knx.groupWrite2ByteFloat("15/0/5", pres);
        Serial.println("Sent KNX Telegramm to 15/0/5 --> success ")+ success;
        success = knx.groupWrite2ByteFloat("15/0/6", hum);
        Serial.println("Sent KNX Telegramm to 15/0/6 --> success ")+ success;
        //success = knx.groupWrite2ByteFloat("15/0/7", wind_speed);
        success = knx.groupWrite2ByteFloat("15/0/7", prev_max_wind_speed);
        Serial.println("Sent KNX Telegramm to 15/0/7 --> success ")+ success;   
        success = knx.groupWrite2ByteFloat("15/0/8", sensorValue);
        //success = knx.groupWrite2ByteFloat("15/0/8", wind_speed);
        Serial.println("Sent KNX Telegramm to 15/0/8 --> success ")+ success;   
  /*
  //Serial.println(success);
  Serial.print("EpromSetting1: "); Serial.println(readFromEEPROM(0));
  Serial.print("EpromSetting2: "); Serial.println(readFromEEPROM(1));
  Serial.print("EpromSetting3: "); Serial.println(readFromEEPROM(2));
  Serial.println(SWversion);
  char buffer_setting1[64];
  readFromEEPROM(0).toCharArray(buffer_setting1, 64);
  char *setting1 = buffer;
  char buffer_pass[64];
  readFromEEPROM(1).toCharArray(buffer_pass, 64);
  char *pass = buffer;
  Serial.print("setting1: "); Serial.println(setting1);
  Serial.print("PASS: "); Serial.println(pass);
  */

        prev_max_wind_speed = 0.0; // reset previous maximum windspeed
        digitalWrite(LED2, LOW); // Display activity


    }
    

 
}

float mapfloat(float x, float in_min, float in_max, float out_min, float out_max)
{
  float returnValue = (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
  if (returnValue >= 0) {
  return returnValue;
  } else {
  return 0;
  }
}


void serialEvent2() {
  //digitalWrite(LED_yellow, HIGH); // for debugging only
  Serial.println("knx.serialEvent(); line1");
  KnxTpUartSerialEventType eType = knx.serialEvent();
  Serial.println("knx.serialEvent();Line2");
   
  if (eType == TPUART_RESET_INDICATION) {
    Serial.println("Event TPUART_RESET_INDICATION");
    
  }
  else if (eType == UNKNOWN) {
    Serial.println("Event UNKNOWN");
  }
  else if (eType == KNX_TELEGRAM) {
    Serial.println("Event KNX_TELEGRAM");
    KnxTelegram* telegram = knx.getReceivedTelegram();
    // Telegrammauswertung auf KNX (bei Empfang immer notwendig)
    String target =
      String(0 + telegram->getTargetMainGroup())   + "/" +
      String(0 + telegram->getTargetMiddleGroup()) + "/" +
      String(0 + telegram->getTargetSubGroup());

    // Here you have the telegram and can do whatever you want
    if (telegram->getCommand() == KNX_COMMAND_WRITE) {
      // Auswertung des empfangenen KNX-Telegrammes mit Schreibbefehl (Flag) -> Aktion
      if (target == "15/0/0") {
        int received_15_0_0 = telegram->getBool();
        Serial.print("Empfangener wert");
        Serial.println(received_15_0_0);
        if (received_15_0_0) {
          digitalWrite(OUT1, HIGH);
        }
        else {
          digitalWrite(OUT1, LOW);
        }
      }
      if (target == "15/0/1") {
        int received_15_0_1 = telegram->getBool();
        Serial.print("Empfangener wert");
        Serial.println(received_15_0_1);
        if (received_15_0_1) {
          digitalWrite(OUT2, HIGH);
        }
        else {
          digitalWrite(OUT2, LOW);
        }
      }
//*
    }
  }
  // digitalWrite(LED_yellow, LOW); // for debugging only
}

// ---------------------------------------- configuration service ----------------------------------------

void saveToEEPROM(int storage, String configValue) {
  configValue.toCharArray(buffer, 16);
  int i = 0;
  for (int address = (storage * 16); address < (storage * 16) + 16; address++) {
    EEPROM.write(address, buffer[i] );
    i++;
    if (buffer[i] == 0)break;
  }
  EEPROM.commit();
}
String readFromEEPROM(int storage) {
  String configValue = "";
  for (int address = (storage * 16); address < (storage * 16) + 16; address++) {
    if (EEPROM.read(address) == 0)break;
    configValue += char(EEPROM.read(address));
  }
  return configValue;
}

void clearEEPROM () {
  for (int i = 0 ; i < EEPROM_SIZE; i++) {
    EEPROM.write(i, 0);
  }
  EEPROM.commit();
}
  

}

Comments powered by CComment