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