Raumgerät Light für UDP-Verbindung mit BSB-LAN Adapter

Begonnen von fabulous, 26 April 2020, 12:50:53

Vorheriges Thema - Nächstes Thema

fabulous

Moin,

in Anlehung an die "Raumgerät Light"-Variante von Andreas29 (https://forum.fhem.de/index.php/topic,91867.0.html) habe ich mir eine Lösung geschaffen, die mit dem BSB-LAN Adapter (https://forum.fhem.de/index.php/topic,29762.0.html) via UDP kommuniziert.

Grundlage ist ein Arduino Uno mit Ethernet Shield, einem 20x4 LCD sowie einem Taster als Präsenztaste.

Aus dem Arduino läuft einen eigenständiger Code; beim BSB-LAN Adapter müssen die "Custom"-Dateien entsprechend erweitert werden.

Code und Fotos stelle ich nachfolgend ein.

Gruß
Fabian

fabulous


fabulous

#2
Code RGLU.ino, v0.01


//RaumGerät Light UDP v0.01
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <LiquidCrystal_I2C.h>

//IP adress and port of RG
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 0, 42);
unsigned int port = 28001;
//IP adress and UDP port of BSB-LAN adapter
IPAddress RxIP(192, 168, 0, 88);
unsigned int RxUDPport = 28000;
const int udp_buff_size = 16;
char RxBuffer[udp_buff_size];
unsigned long t_act, t_old;

int maxtry = 5; //maximum tries for connection etc. with BSB-LAN

struct pv_Rx {
  int par;
  int val;
};

struct pv_RG {
  double OT;  //outside temperature
  double RT;  //room temperature
  double WT;  //water temperature
  double RT_t;  //room temperature, target
  double RT_c;  //room temperature, comfort
  double RT_r;  //room temperature, reduced
  boolean presence_state;
  boolean presence_error;
  boolean water_state;
  boolean burner_state;
};

struct pv_RG dat;
struct pv_Rx pv;
unsigned int sep_pos = 5;
unsigned int TM_size = 16;
char ps[5];
char vs[10];
boolean presence_button_pressed;
boolean button_pres_stat_act;
boolean button_pres_stat_old;
boolean isconnected;
boolean wait;

EthernetUDP Udp;

LiquidCrystal_I2C LCD(39, 20,4);

byte degree[8] = {B01110, B01010, B01110, B00000, B00000, B00000, B00000, B00000};
byte sun[8] = {0b00100, 0b10101, 0b01110, 0b11011, 0b01110, 0b10101, 0b00100, 0b00000};
byte moon[8] = {0b00111, 0b01110, 0b11100, 0b11100, 0b11100, 0b01110, 0b00111, 0b00000};
byte snow[8] = {0b01010, 0b00100, 0b10101, 0b01110, 0b10101, 0b00100, 0b01010, 0b00000};
byte flame[8] = {0b00010, 0b00100, 0b01100, 0b01110, 0b01010, 0b01010, 0b00100, 0b11011};
byte water[8] = {0b00000, 0b01110, 0b00101, 0b11111, 0b10001, 0b10000, 0b00000, 0b00000};

void requestBC() {
  //sprintf(TxBuffer, "%.7s", "REQBC@1");
  Udp.beginPacket(RxIP, RxUDPport);
  //Udp.print(TxBuffer);
  Udp.print("REQBC@0000000001");
  Udp.endPacket();
}

void RxUDP() { 
  int RxPacket = Udp.parsePacket();
  if(RxPacket) {
    Udp.read(RxBuffer, udp_buff_size);
    isconnected = true;
  }
}

//determine presence state
void determine_presence_state() {
  if (dat.RT_t == dat.RT_c) {
    dat.presence_state = true;
    dat.presence_error = false;
  }
  if (dat.RT_t == dat.RT_r) {
    dat.presence_state = false;
    dat.presence_error = false;
  }
  if (dat.RT_t != dat.RT_c && dat.RT_t != dat.RT_r)
    dat.presence_error = true;
}

void get_button_state() {
  button_pres_stat_act = digitalRead(8);
  //Pin uses PULL UP resistance -> "not pressed" means HIGH
  if (button_pres_stat_act && button_pres_stat_old) { //not pressed and not pressed before
    presence_button_pressed = false; //do not detect as pressed
  }
  if (!button_pres_stat_act && !button_pres_stat_old) { //pressed and pressed before
    presence_button_pressed = false; //do not detect as pressed
  }
  if (button_pres_stat_act && !button_pres_stat_old) { //not pressed and pressed before
    presence_button_pressed = false; //do not detect as pressed
  }
  if (!button_pres_stat_act && button_pres_stat_old) { //pressed and not pressed before
    presence_button_pressed = true; //detect as pressed
    delay(100);  //debounce
  }
  button_pres_stat_old = button_pres_stat_act;
}

struct pv_Rx GetParamVal() {
  //all TM has to be:
  //[5 character]@[10 character]
  //5 character = parameter number acc. to RVS43.122, 0 at LSB if needed
  //@ = separator
  //10 character = value
  char ps[5];
  char vs[10];
  int i, j;
  struct pv_Rx pv;
  pv.par = 0;
  pv.val = 0;
  //get parameter
  j=0;
  for(i=0;i<sep_pos; i++){
    ps[j] = RxBuffer[i];
    j++;
  }
  pv.par = atoi(ps);
  //get value
  j=0;
  for(i=sep_pos+1;i<TM_size; i++){
    vs[j] = RxBuffer[i];
    j++;
  }
  vs[j]='\0'; //I don't know why this is necessary, maybe some char/pointer thing...
  pv.val = atoi(vs);
  return pv;
}

void EvalParamVal() {
  pv = GetParamVal();
  if (pv.par > 0) {
    Serial.print(pv.par);
    Serial.print("@");
    Serial.println(pv.val);
  }
  if (pv.par == 8700) //outside temperature
    dat.OT = 0.1 * pv.val;
  if (pv.par == 8740) //room temperature
    dat.RT = 0.1 * pv.val;
  if (pv.par == 8830) //water temperature
    dat.WT = 0.1 * pv.val;
  if (pv.par == 8741) //room temperature, target
    dat.RT_t = 0.1 * pv.val;
  if (pv.par == 710) //room temperature, comfort
    dat.RT_c = 0.1 * pv.val;
  if (pv.par == 712) //room temperature, reduced
    dat.RT_r = 0.1 * pv.val;
     
  if (pv.par == 8300) {//burner state
    //evaluate burner state
    if (pv.val == 1)
      dat.burner_state = true;
    else
      dat.burner_state = false;
  }
   
  if (pv.par == 8003) {//water heating state
    //evaluate TWW state
    if (pv.val == 69 || (pv.val >= 92 && pv.val <= 97))
      dat.water_state = true;
    else
      dat.water_state = false;   
  }
}

void UpdateLCD(){
  LCD.setCursor(0,0);
  LCD.print("Au\xE2");
  LCD.print("entemp: ");
  LCD.print(dat.OT);
  LCD.setCursor(15,0);
  LCD.print(char(0));
  LCD.print("C");
 
  LCD.setCursor(0,1);
  LCD.print("Raumtemp : ");
  LCD.print(dat.RT);
  LCD.setCursor(15,1);
  LCD.print(char(0));
  LCD.print("C");
 
  LCD.setCursor(0,2);
  LCD.print("TWW Temp : ");
  LCD.print(dat.WT);
  LCD.setCursor(15,2);
  LCD.print(char(0));
  LCD.print("C");

  //presence state
  if (dat.presence_state) {
    LCD.setCursor(19,0);
    LCD.print(char(1)); //sun enable
    LCD.setCursor(19,1);
    LCD.print(" "); //moon disable
  }
  else {
    LCD.setCursor(19,0);
    LCD.print(" "); //sun disable
    LCD.setCursor(19,1);
    LCD.print(char(2)); //moon enable
  }
  //presence error
  if (dat.presence_error) {
    LCD.setCursor(19,0);
    LCD.print("#"); //sun disable
    LCD.setCursor(19,1);
    LCD.print("#"); //moon disable
  }
   
  //burner state
  LCD.setCursor(19,3);
  if (dat.burner_state)
    LCD.print(char(4)); //flame enable
  else
    LCD.print(" "); //flame disable
   
  //water state
  LCD.setCursor(19,2);
  if (dat.water_state)
    LCD.print(char(5)); //water enable
  else
    LCD.print(" "); //water disable
}

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(8, INPUT_PULLUP);
  presence_button_pressed = false;
  button_pres_stat_act = true;
  button_pres_stat_old = true;
  isconnected = false;
  int i;

  Ethernet.begin(mac,ip);
  delay(500);
  Udp.begin(port);
  delay(500);

  Serial.begin(115200);
  delay(500);

  LCD.init();
  LCD.clear();
  LCD.backlight();
  LCD.createChar(0, degree);
  LCD.createChar(1, sun);
  LCD.createChar(2, moon);
  LCD.createChar(3, snow);
  LCD.createChar(4, flame);
  LCD.createChar(5, water);

  LCD.setCursor(0,0);
  LCD.print("Connecting...");
  delay(500);
  for (i=0; i<=maxtry; i++) {
    //request first BC to check connection
    requestBC();
    delay(1000);
    RxUDP(); //sets "isconnected" to true if UDP packet received
    Serial.println(i);
    if (isconnected)
      break;
  }
  //determine_presence_state();
  LCD.setCursor(0,0);
  if (!isconnected) {
    LCD.print("Connection failed!  ");
    LCD.setCursor(0,3);
    LCD.print("Error #503");
    delay(2000);
  }
  else {
    LCD.print("Connected!        ");
    delay(2000);
  }
  LCD.clear();

  UpdateLCD();
  t_old=millis();
}

void loop() {
  int i;
  //check for new UDP packets
  RxUDP();
  //evaluate what has been received
  EvalParamVal();
  //determine presence state based on room target temperature
  determine_presence_state();
  //check if presence button ("Präsenztaste") was pressed on RG
  get_button_state();
  if (presence_button_pressed) {
    double RT_t_old = dat.RT_t;
    LCD.setCursor(0,3);
    LCD.print("Bitte warten...");
    //transmit request to BSB_LAN for change of presence_state
    Udp.beginPacket(RxIP, RxUDPport);
    Udp.print("!PRES@0000000001");
    Udp.endPacket();
    wait = true;   
    for (i=0; i<=maxtry; i++) {
      if (RT_t_old == dat.RT_t) {//if no change
        //wait for RT_t to be updated
        RxUDP(); //sets "isconnected" to true if UDP packet received
        EvalParamVal();
        delay(2000);
      }
      else {
        wait = false;
        LCD.setCursor(0,3);
        LCD.print("               ");
        break;
      }
      //Serial.println(i);
    }
    //invert presence state
    if (!wait) {//target room teperature was changed by heating before max try was reached
      dat.presence_state = !dat.presence_state;
      //update LCD
      LCD.clear();
      LCD.setCursor(0,0);
      if (dat.presence_state && !dat.presence_error) {
        LCD.print("Pr\xE1");
        LCD.print("senz: EIN");
        LCD.setCursor(0,1);
        LCD.print("Heizen auf");
        LCD.setCursor(0,2);
        LCD.print("Komfortsollwert");
      }
      if (!dat.presence_state && !dat.presence_error) {
        LCD.print("Pr\xE1");
        LCD.print("senz: AUS");
        LCD.setCursor(0,1);
        LCD.print("Heizen auf");
        LCD.setCursor(0,2);
        LCD.print("Reduziersollwert");
      }
      delay(2000);
      //RxUDP(); //check for new values to make sure presence was really changed
      //determine_presence_state(); //update presence state
      LCD.clear();
      UpdateLCD(); //show new presence state
    }
    else { //no answer received in time from BSB-LAN
      LCD.setCursor(0,3);
      LCD.print("Error #503     ");
      delay(2000);
      LCD.setCursor(0,3);
      LCD.print("               ");
    }
  }
  t_act = millis();
  if (t_act - t_old > 5000) {
    UpdateLCD();
    t_old = t_act;
  }
  //reset Rx buffer
  sprintf(RxBuffer, "%d", 0);
}


Code BSB_lan_custom.h


//RGLU, custom code for loop function
//for RGLU v0.01

//check for new UDP packets
RxUDP();
//presence state changed in RG
if (!strcmp(RxBuffer, "!PRES@0000000001")) {
  Serial.println("Request to change presence status");
  pv.RT_t = (int)(atof(query(8741,8741,0))*10);
  pv.RT_c = (int)(atof(query(710,710,0))*10);
  pv.RT_r = (int)(atof(query(712,712,0))*10);
  if (pv.RT_t == pv.RT_c) { //if currently in comfort mode
    Serial.println("Currently, RT_t = comfort, change to reduced / 'not present'");
    set(701, "1", 1);  //set heating to "reduced"
  }
  if (pv.RT_t == pv.RT_r) { //if currently in reduced mode
    Serial.println("Currently, RT_t = reduced, change to comfort / 'present'");
    set(701, "0", 1);  //set heating to "comfort"
  }
  //delay (1);
  //send new room target temperature
  pv.RT_t = (int)(atof(query(8741,8741,0))*10);
  //Serial.print("RT_t set to :");
  //Serial.println(pv.RT_t);
  Udp.beginPacket(RxIP, RxPort);
  sprintf(TxBuffer, "%.5i@%.10i", 8741, pv.RT_t);
  Udp.print(TxBuffer);
  Udp.endPacket();
}
//broadcast request by RG
if (!strcmp(RxBuffer, "REQBC@0000000001")) {
  Serial.println("BC request ... send BC data");
  pv.RT_t = (int)(atof(query(8741,8741,0))*10);
  pv.RT_c = (int)(atof(query(710,710,0))*10);
  pv.RT_r = (int)(atof(query(712,712,0))*10);
  pv.OT = (int)(atof(query(8700,8700,0))*10);
  pv.RT = (int)(atof(query(8740,8740,0))*10);
  pv.WT = (int)(atof(query(8830,8830,0))*10);
  pv.water_state = (atoi)(query(8003,8003,0));
  pv.burner_state = (atoi)(query(8300,8300,0));
  Serial.println(pv.OT);
  //send broadcast
  TxBC();
}
//send BC data periodically every ~30 seconds
t_act = millis();
if (t_act - t_old > 30000) {
  Serial.println("Send periodic BC data");
  pv.RT_t = (int)(atof(query(8741,8741,0))*10);
  pv.RT_c = (int)(atof(query(710,710,0))*10);
  pv.RT_r = (int)(atof(query(712,712,0))*10);
  pv.OT = (int)(atof(query(8700,8700,0))*10);
  pv.RT = (int)(atof(query(8740,8740,0))*10);
  pv.WT = (int)(atof(query(8830,8830,0))*10);
  pv.water_state = (atoi)(query(8003,8003,0));
  pv.burner_state = (atoi)(query(8300,8300,0));
  //send broadcast 
  TxBC();
  t_old = t_act;
}
//reset Rx buffer
sprintf(RxBuffer, "%d", 0);


Code BSB_lan_custom_global.h


//RGLU, custom code for global section
//for RGLU v0.01

#include <stdlib.h>

//UDP port of BSB-LAN
unsigned int UDPportBSB = 28000;
//IP adress and port of RG
IPAddress RxIP(192, 168, 0, 42);
unsigned int RxPort = 28001;
const int udp_buff_size = 16;
char RxBuffer[udp_buff_size];
char TxBuffer[udp_buff_size];
unsigned long t_act, t_old;

struct pv_BSB {
  int OT;  //outside temperature
  int RT;  //room temperature
  int WT;  //water temperature
  int RT_t;  //room temperature, target
  int RT_c;  //room temperature, comfort
  int RT_r;  //room temperature, reduced
  int water_state;
  int burner_state;
};

struct pv_BSB pv;

EthernetUDP Udp;

void RxUDP() //read UDP packet

  int RxPacket = Udp.parsePacket();
  if(RxPacket) {
    Udp.read(RxBuffer, udp_buff_size);
    Serial.print("RxUDP: ");
    Serial.println(RxBuffer);
  }
}

void TxBC(){
    Serial.println("Send UDP data: ");
    //send outside temperature
    Udp.beginPacket(RxIP, RxPort);
    sprintf(TxBuffer, "%.5i@%.10i", 8700, pv.OT);
    Serial.println(TxBuffer);
    Udp.print(TxBuffer);
    Udp.endPacket();
    delay(100);
    //send room temperature
    Udp.beginPacket(RxIP, RxPort);
    sprintf(TxBuffer, "%.5i@%.10i", 8740, pv.RT);
    Serial.println(TxBuffer);
    Udp.print(TxBuffer);
    Udp.endPacket();
    delay(100);
    //send water temperature
    Udp.beginPacket(RxIP, RxPort);
    sprintf(TxBuffer, "%.5i@%.10i", 8830, pv.WT);
    Serial.println(TxBuffer);
    Udp.print(TxBuffer);
    Udp.endPacket();
    delay(100);
    //send burner status
    Udp.beginPacket(RxIP, RxPort);
    sprintf(TxBuffer, "%.5i@%.10i", 8300, pv.burner_state);
    Serial.println(TxBuffer);
    Udp.print(TxBuffer);
    Udp.endPacket();
    delay(100);
    //send water status
    Udp.beginPacket(RxIP, RxPort);
    sprintf(TxBuffer, "%.5i@%.10i", 8003, pv.water_state);
    Serial.println(TxBuffer);
    Udp.print(TxBuffer);
    Udp.endPacket();
    delay(100);
    //send room target temperature
    Udp.beginPacket(RxIP, RxPort);
    sprintf(TxBuffer, "%.5i@%.10i", 8741, pv.RT_t);
    Serial.println(TxBuffer);
    Udp.print(TxBuffer);
    Udp.endPacket();
    delay(100);
    //send room comfort temperature
    Udp.beginPacket(RxIP, RxPort);
    sprintf(TxBuffer, "%.5i@%.10i", 710, pv.RT_c);
    Serial.println(TxBuffer);
    Udp.print(TxBuffer);
    Udp.endPacket();
    delay(100);
    //send room reduced temperature
    Udp.beginPacket(RxIP, RxPort);
    sprintf(TxBuffer, "%.5i@%.10i", 712, pv.RT_r);
    Serial.println(TxBuffer);
    Udp.print(TxBuffer);
    Udp.endPacket();
    delay(100);       
}


Code BSB_lan_custom_setup.h


//RGLU, custom code for setup function
//for RGLU v0.01

Udp.begin(UDPportBSB);
t_old=millis();  //counter for periodic broadcast

Schotty

Moin Fabian,
wärst du damit einverstanden, wenn ich das mit als 'Bastel'-Beispiel ins BSB-LAN-Handbuch aufnehme?
Gruß
Handbuch zur BSB-LAN Hard- & Software (Anbindung v. Heizungsreglern, u.a. von Brötje & Elco):
https://1coderookie.github.io/BSB-LPB-LAN/


Schotty

Handbuch zur BSB-LAN Hard- & Software (Anbindung v. Heizungsreglern, u.a. von Brötje & Elco):
https://1coderookie.github.io/BSB-LPB-LAN/

Maista

@fabulous

Jetzt fehlt nur noch die ESP-Variante ;)

Schönen Sonntag

Gerd

fabulous

#7
Moin,

hier noch ein paar erläuternde Worte:

Auf beiden Arduinos (BSB-LAN Adapter und RGLU) läuft ein UDP-Service. Damit ist es möglich, UDP-Pakete sowohl zu versenden als auch zu empfangen. Der BSB-Lan Adapter verwendet dazu Port 28000, das RGLU verwendet Port 28001. Theoretisch sind auch andere Ports möglich; ich habe welche gewählt die durch keine von mir verwendete Software benutzt werden. Siehe auch: https://de.wikipedia.org/wiki/Liste_der_standardisierten_Ports#Registrierte_Ports:_1024%E2%80%9349151

Der BSB-LAN Adapter sendet alle ca. 30 Sekunden ein Broadcast-Paket mit folgenden Parametern:
- RT_t = Parameter 8741; derzeitige Raumsolltemperatur
- RT_c = 710; Komforttemperatur
- RT_r = 712; Reduziertemperatur
- OT = 8700; Aussentemperatur
- RT = 8740; Raumtemperatur
- WT = 8830; Wassertemperatur
- water_state = 8003; Trinkwasserstatus
- burner_state = 8300; Brennerstufe 1 aktiv

Darüberhinaus reagiert der BSB-LAN Adapter auf einen Broadcast-Request (REQBC@0000000001) des RGLU sowie ein Drücken der Präsenztaste am RGLU (!PRES@0000000001).

Das RGLU prüft permanent auf empfangene UDP-Pakete und wertet diese aus. Nach der Auswertung werden die entsprechenden Infos auf dem LCD bereitgestellt. Aussentemperatur, Raumtemperatur und Wassertemperatur werden direkt angezeigt.
Der Trinkwasserstatus wird verwendet, um ein entsprechendes Symbol (Wasserhahn) anzuzeigen, wenn das Wasser gerade erwärmt wird.
"Brennerstufe 1" wird verwendet, um ein entsprechendes Symbol (Flamme) anzuzeigen, wenn der Brenner läuft.
Raumsolltemperatur, Komfortemperatur und Rediziertemperatur werden verwendet, um entsprechend das Symbol Sonne/Mond anzuzeigen.

Beim Drücken des Tasters (Präsenztaste) am RGLU wird eine UDP-Nachricht an den BSB-LAN Adapter gesendet. Dieser setzt per set(701, ...) die Heizung in den entsprechenden Modus. Anschließend wird die neue Solltemperatur (im Erfolgsfall wurde diese durch den set(701, ...) in der Heizung geändert) ans RGLU zurückgeschickt. Dort wird der neue Präsenzstatus bestimmt und entsprechend zurückgemeldet.

Es existiert nur eine minimale Fehlerbehandlung; alle Pakete verwenden den Aufbau "ppppp@vvvvvvvvvv"; also 5 Stellen für den Parameter, einen Separator (@) und 10 Stellen für den Wert.
Es werden nur Integerwerte verwendet; daher werden alle Temperaturen vor dem Senden mit dem Faktor 10 multipliziert und nach dem Empfang mit dem Faktor 0,1 multipliziert. Dadurch ist keine Verwendung von Double-Werten für die Übertragung bzw. Erkennung von Kommata etc. nötig.

Das Ganze soll noch in eine Box gepackt werden; diese soll an der Haustür platziert werden. Das Hauptaugemerk liegt in der Präsenztaste; ich habe zwar ein RGT, allerdings befindet sich das RGT im Referenzraum und dieser ist maximal weit von der Haustür entfernt. Es ist zwar möglich, ein zweites RGT zu verwenden; aber an diesem ist dann die Präsenzfunktion (soweit ich weiss) deaktiviert.

Gruß
Fabian

Schotty

Zitat von: fabulous am 26 April 2020, 14:05:02
Der BSB-LAN Adapter sendet alle ca. 30 Sekunden ein Broadcast-Paket mit folgenden Parametern:
...
Darüberhinaus reagiert der BSB-LAN Adapter auf einen Broadcast-Request (REQBC@0000000001) des RGLU sowie ein Drücken der Präsenztaste am RGLU (!PRES@0000000001).

Das RGLU prüft permanent auf empfangene UDP-Pakete und wertet diese aus.
Vorweg: Ich habe nicht alles verstanden, aber das mit den Broadcasts finde ich prinzipiell interessant und wäre evtl auch für FHEM und andere HA-Systeme nützlich, oder?
Soweit ich weiß, kann BSB-LAN ja bisher keine eigenständigen Broadcasts versenden: https://1coderookie.github.io/BSB-LPB-LAN/kap15.html#1513-kann-bspw-fhem-auf-bestimmte-broadcasts-lauschen
Könntest du das vielleicht auch nochmal im eigentlichen BSB-LAN-Thread posten? Ich könnte mir vorstellen, dass das auch für @freetz und eine etwaige generelle Implementierung in BSB-LAN interessant sein könnte?!
Gruß
Handbuch zur BSB-LAN Hard- & Software (Anbindung v. Heizungsreglern, u.a. von Brötje & Elco):
https://1coderookie.github.io/BSB-LPB-LAN/

fabulous

#9
Moin,

@Schotty:
Kannst du etwas genauer erläutern, was das Ziel ist? Ich habe noch nicht mit FHEM gearbeitet.

Der Grund, warum ich UDP verwende, ist, dass es ein sehr einfaches Protokoll ist und sich der Sender nicht wirklich darum kümmert, was mit seinem gesendeten Paket passiert - sozusagen "fire and forget".
Ich habe den Begriff "Broadcast" verwendet, weil ich im Hinterkopf habe, noch ein zweites RGLU im Badezimmer zu installieren, allerdings mit einem "TWW Push"-Button - der BSB-LAN Adapter soll nicht übermäßig belastet werden und das Paket mit den ganzen Werten nur einmal an alle Empfänger gleichzeitig senden anstatt an jeden Empfänger separat. UDP beherrscht diesen "Broadcast" theoretisch. Ich habe es aber noch nicht umgesetzt. Es wird derzeit nur an einen einzigen Empfänger gesendet.

@Maista: was meinst du in diesem Zusammenhang mit "ESP"? Hilf mir mal auf die Sprünge ...

Gruß
Fabian

Schotty

So wie ich es verstanden habe machst du im Grunde das, was auch der Heizungsregler selbst schon von Haus aus macht, nämlich bestimmte Werte/Parameter in bestimmten Intervallen einfach über den Bus schicken. Finde ich gut und ließe sich bestimmt gut nutzen, wenn man die Parameter entspr konfigurieren/definieren kann. Eine gute Lösung, um bspw nicht immer aktiv abfragen zu müssen (ob nun mit FHEM oder einer anderen HA-Lösung ist dabei ja gleichgültig) und wie du jetzt bspw ein Status-Display o.ä. damit zu basteln..
Ein bestimmtes 'Ziel hinsichtlich FHEM' habe ich da nicht im Sinn, mir ging's nur darum, dass eine solche 'broadcast'-Funktion noch nicht in BSB-LAN implementiert ist. Also bisher kann/muss man entweder aktiv pollen oder via MQTT schicken lassen.

Maista meinte mit ESP sicherlich, dass er (und bestimmt auch andere ;) ) sich diesen Code lauffähig für ESP-basierte Plattformen (Wemos D1, nodeMCU etc) wünscht, so dass man eben anstelle eines Uno+LAN-Shield einfach irgendwo im Haus eine WLAN-basierte Lösung einsetzen könnte. Hätte wirklich was.. ;)
Handbuch zur BSB-LAN Hard- & Software (Anbindung v. Heizungsreglern, u.a. von Brötje & Elco):
https://1coderookie.github.io/BSB-LPB-LAN/

fabulous

Moin,

ich verstehe.

Wenn das Zielsystem UDP-fähig ist, könnte meine Lösung entsprechend angepasst werden.

Gruß
Fabian


Schotty

Yupp,zum beispiel,andere varianten mit micro-usb-port (weils praktisch ist  ;) ) wären bspw auch 'wemos d1 mini' (gibts u.a. auch als 'pro' mit optionaler externer antenne)). Is nochmal etwas kleiner als ein nodemcu, aber bietet im grunde gleich viel.
Allen gemein ist,dass darauf ein esp8266 verbaut ist. Ist quasi der wlan-chip mit leistungsfähigem mikrocontroller. Den gibts zwar auch einzeln,is aber m.m.n. nich so praktisch benutzbar (bzgl flashen,strom etc). Die dinger sind mittlerweile in unzähligen komponenten verbaut,bspw sonoff, lampen mit wlan- anbindung und wat nich noch alles..
Haben mehr ram,flash,power etc als jeder arduino.
Werden gerne eingesetzt,wo eine relativ unkomplizierte komponentenanbindung via wlan gewünscht ist. Für nicht-programmierer mit bspw tasmota, espeasy, espurna, esphome auch relativ unkompliziert zu konfigurieren. Für programmierer aber natürlich auch mit arduino-ide o.ä. programmierbar.

Der nachfolger vom esp8266 ist der esp32, hat mehr speicher,power,bluetooth an board und noch etliches mehr. Für die 'normalen' dinge reicht der esp8266 aber i.d.r. dicke.
Handbuch zur BSB-LAN Hard- & Software (Anbindung v. Heizungsreglern, u.a. von Brötje & Elco):
https://1coderookie.github.io/BSB-LPB-LAN/

Schotty

..fällt mir gerade noch ein: pass auf bei sog. 'v3 lolin' nodemcu's,das sind wohl 'alte' varianten und außerdem sind sie größer als die v2.
Gibt aber wohl im grunde eigtl eh nur zwei 'eigentliche' nodemcu-typen,s.hier: https://www.mikrocontroller.net/topic/412609

Wemos d1 haben noch nen extra 5v-pin zur spannungsversorgung von komponenten,wenn du das modul selbst per mini-usb-buchse mit strom versorgst. Der fehlt bei nodemcu (v2),aber dort kann man afaik in dem fall 'vin' zum abgreifen der 5v nutzen.

Aber achtung: die gpios des esp8266 (und aller darauf basierenden varianten, also auch wemos d1, nodemcu etc) sind laut datenblatt nur 3,3v-kompatibel! Manche vertragen mit glück auch mal 5v,aber das ist bzw kann ein glücksspiel sein. Also für 5v-signale dann lieber sicherheitshalber spannungsteiler o.ä. nutzen oder einen mehr bestellen  ;)
Handbuch zur BSB-LAN Hard- & Software (Anbindung v. Heizungsreglern, u.a. von Brötje & Elco):
https://1coderookie.github.io/BSB-LPB-LAN/

Schotty

#15
..nur für den fall,dass du die noch nicht kennst: es gibt 0.96" oled-displays (spi ssd1306),sind schick und kannst evtl noch mehr drauf darstellen.
Bei pollin gibts kleine gehäuse in unterschiedlichen tiefen, wo alles reinpasst. Bei interesse kann ich morgen nochmal nachgucken und dir nen beispiellink schicken wenn du möchtest..
Handbuch zur BSB-LAN Hard- & Software (Anbindung v. Heizungsreglern, u.a. von Brötje & Elco):
https://1coderookie.github.io/BSB-LPB-LAN/

fabulous

#16
Moin,

ich glaube verstanden zu haben, auf was ihr abzielt.
Das Raumgerät soll ESP-basiert sein, richtig?
Ihr wollt keine Ethernetkabel verlegen.

Ich kann mir das mal anschauen.

Gruß
Fabian

Schotty

Moin Fabian,
ja klasse, ich bin gespannt :)

Zitat von: fabulous am 26 April 2020, 15:42:54
weil ich im Hinterkopf habe, noch ein zweites RGLU im Badezimmer zu installieren, allerdings mit einem "TWW Push"-Button
Nur so ein Gedanke: Wieso stattest du die nicht direkt mit zwei Tastern aus, einen für TWW-Push, einen als Präsenztaste (also so wie ein RGT)? Wenn du den Taster nur im Badezimmer hast und dann dort erst bei Bedarf drückst, dauert es ja auch nochmal eine ganze Weile, bis das TWW entsprechend aufgeheizt ist.

Gruß
Handbuch zur BSB-LAN Hard- & Software (Anbindung v. Heizungsreglern, u.a. von Brötje & Elco):
https://1coderookie.github.io/BSB-LPB-LAN/

fabulous

Moin,

mein Ziel ist es, dass der Code ohne Anpassung auf beiden RGs läuft; der UDP-Request wird ja so gesehen jeweils durch einen Taster ausgelöst. Theoretisch ist dann beides an beiden RGs möglich; praktisch nicht weil ich nur jeweils einen Taster anbringen werde.
Aufgrund der baulichen Situation sehe ich bei mir tatsächlich nur eine XOR- Notwendigkeit für die Taster.

Gruß
Fabian

fabulous

Moin,

kurze Statusmeldung:

- Der UDP Broadcast (gleichzeitiges Senden der Daten an alle Clients im Subnet mit einem einzigen Aufruf) scheint wie geplant zu funktionieren durch das Ersetzen der RxIP von 192.168.0.42 mit 192.168.0.255.
- Die Kompatibilitätsprüfung bzw. Portierung auf ESP-basierte Lösungen scheitert gerade an meinem WinXP Rechner. Die Arduino IDE scheint sich lt. Internetrecherche nicht mit den Wemos D1 Boardinfos zu vertragen. Die Pfade der Bibliotheken etc. laufen ins Leere. Ich muss mal schauen, wie ich hier weiter mache.

Ich warte ausserdem noch auf ein weiteres Uno-Board, da die Nano-Boards in Verbindung mit einem Ethernet Shield irgendwie nicht so wirklich funktionieren.

Gruß
Fabian

Schotty

Moin,
auf die Schnelle:
a) hast du die entspr CH340G-Treiber für den USB-Chip des Wemos bei Win installiert und
b) die entspr ESP8266-Board-Lib in der ArduIDE hinzugefügt? (Werkzeuge -> Board -> Boardverwalter -> "esp8266" oder "wemos" eingeben)
U.a. hier ist es (wenn auch nur für Mac) sonst auch nochmal ganz gut beschrieben: https://www.xgadget.de/anleitung/wemos-so-laeuft-die-installation-in-der-arduino-ide-ab/
Gruß
Handbuch zur BSB-LAN Hard- & Software (Anbindung v. Heizungsreglern, u.a. von Brötje & Elco):
https://1coderookie.github.io/BSB-LPB-LAN/

fabulous

#21
Moin,

ja, kann auch das Board auswählen.

Ich hatte beim Kompilieren erst diese Ausgabe:

fatal error: bits/c++config.h: No such file or directory

#include <bits/c++config.h>


Das konnte ich lösen, ein entsprechendes Kopieren in das bits-Verzeichnis (wie auf diversen Seiten vorgeschlagen) war die Lösung.

Dann gibt es jetzt aber diese Ausgabe:


fatal error: bits/stl_iterator_base_types.h: No such file or directory

#include <bits/stl_iterator_base_types.h>


Und dafür finde ich keine Lösung.

EDIT: siehe Beitrag 1
https://www.roboternetz.de/community/threads/70524-NodeMCU-an-Arduino-IDE-Fehler-beim-Kompilieren

Gruß
Fabian

Schotty

Hmm,also wenn ich die zweite fehlermeldung google,dann kommen ein paar ergebnisse,die sich dabei größtenteils auf winxp beziehen. Scheint bei xp öfter vorzukommen, habs aber nur kurz quergelesen. Hast du n anderes os zur verfügung?
Wenn du magst,kannst du mir die ino sonst mal schicken (email siehe handbuch, adapter@...) od hier einstellen,dann kann ich mal testen,ob ichs hier unter ubuntu problemlos flashen kann. Wird heute zwar nix mehr,aber asap..
Gruß Ulf
Handbuch zur BSB-LAN Hard- & Software (Anbindung v. Heizungsreglern, u.a. von Brötje & Elco):
https://1coderookie.github.io/BSB-LPB-LAN/

Schotty

Moin Fabian,

ich sitze gerade an den Handbuchanpassungen für den Due und wollte bei der Gelegenheit auch gleich deine Raumgeräte-Variante mit aufführen. Kann ich dafür dein Foto mit ins Handbuch nehmen?

Bist du bzgl der ESP-Umsetzung schon weitergekommen? (Btw: Den Code zum Test-Flashen hattest du mir nicht geschickt, oder? Zumindest war auch im Spam-Ordner nichts, was danach aussah..)

Gruß Ulf
Handbuch zur BSB-LAN Hard- & Software (Anbindung v. Heizungsreglern, u.a. von Brötje & Elco):
https://1coderookie.github.io/BSB-LPB-LAN/

fabulous

#24
Moin,

@Schotty: entschuldige bitte die späte Antwort. An meiner Heizung hängt noch ein Haus dran, dessen Renovierung mich relativ viel Zeit kostet.

Natürlich kannst du das Bild verwenden; wenn du noch mehr brauchst, melde dich einfach.

Zum Thema ESP-Portierung:
Ich habe noch keine ESP-speziellen Änderungen am Code vorgenommen. Ich gehe davon aus, das zusätzliche Bibliotheken nötig sind; allerdings kann ich das erst herausfinden, wenn es mir gelingt, den Code zu compilieren - und das funktioniert auf dem XP-Rechner nicht.
Allerdings konnte ich einen Win8 PC auftreiben; ich konnte es allerdings noch nicht ausprobieren.

Das OLED (128x32) habe ich zum Laufen gebracht; mit I2C-Schnittstelle ist es relativ einfach. Ich möchte aber noch ein größeres LCD ausprobieren um mehr darstellen zu können.

Ausserdem habe ich jetzt zwei mögliche Konfigurationen im Code hinterlegt: eine Konfiguration ist für nahe der Haustür mit Präsenzknopf und 20x4 LCD; eine zweite Konfiguration fürs Badezimmer mit TWW Push sowie DHT22-Sensor für Logging von Raumtemperatur und Luftfeuchtigkeit.
Für das OLED möchte ich eine weitere Konfiguration anlegen.

EDIT: Kompilieren auf dem Win8 Rechner läuft ohne Fehler durch. Ich muss aber wohl die Ethernet- und UDP - Aufrufe anpassen.

Gruß
Fabian

Schotty

Hi Fabian,

gar kein Problem, wir haben schließlich alle noch ein Leben neben Heizung und FHEM - und die Heizsaison ist (für die meisten) ja eh quasi durch ;)

Bzgl Bild(er): Dann wäre es schön, wenn du schlussendlich von deinen verschiedenen Lösungen, die du dann selbst nutzt, jeweils ein Bild machen könntest. Dann würde ich die (evtl in der Gesamtansicht im Gehäuse oder nur von der Display-Ansicht, mal sehen) jeweils mit aufführen. Eilt aber nicht!

Klasse, dass du verschiedene Varianten erstellst, da dürfte dann ja wirklich für jeden was dabei sein! Danke!

Dann noch viel Spaß und Erfolg beim Renovieren :)

Gruß
Handbuch zur BSB-LAN Hard- & Software (Anbindung v. Heizungsreglern, u.a. von Brötje & Elco):
https://1coderookie.github.io/BSB-LPB-LAN/

fabulous

Moin,

ich kann erste Erfolge vermelden.
Die Portierung auf Nodemcu v2 mit 0.96 OLED funktioniert im Prinzip.
Es gibt allerdings noch Kinderkrankheiten.

Gruß
Fabian

fabulous


Schotty

Whoa wie cool! Das ging jetzt aber fix! :)
Kennst du diese 0.96" OLEDs https://www.amazon.de/AZDelivery-Display-Arduino-Raspberry-gratis/dp/B01L9GC470/
Die meinte ich damals eigtl, die haben 128 x 64 Zeichen, vielleicht wäre das was?
Handbuch zur BSB-LAN Hard- & Software (Anbindung v. Heizungsreglern, u.a. von Brötje & Elco):
https://1coderookie.github.io/BSB-LPB-LAN/

fabulous

Moin,

ich musste quasi nur die Ethernet- gegen eine Wifi-Lib tauschen; gleiches für die UDP-Lib.
Der größte Aufwand ist die Parallelität von Arduino, ESP, LCD und OLED im gleichen Code.

Ich warte derzeit noch auf ein größeres OLED mit 128x64 Pixeln.

Gruß
Fabian

fabulous

Moin,

anbei eine überarbeitete Version.

Die BSB_lan...-Dateien müssen mit auf den BSB-LAN-Adapter geflasht werden. Ausserdem muss RGLU_types.h mit dazu.

Alle RGLU...-Dateien werden für das Raumgerät benötigt.

Die wichtigste Datei ist "RGLU_def.h"; hiermit können die einzelnen Konfigurationen ausgewählt ("RG_CONF") werden oder neue selbst definiert werden.
Derzeit sind drei Konfigurationen hinterlegt:
- 0: Arduino Uno mit Ethernet Shield, 20x4 LCD und Präsenztaste
- 1: Arduino Uno mit Ethernet Shield und 16x2 LCD
- 2: NodeMCU v2 mit 128x32 OLED (hierfür müssen SSID und pwd in "RGLU_pass.h" angepasst werden)

Die IP-Adressen bzw. die Netzwerk-Konfiguration ist ebenfalls anzupassen.

Die Funktion "TWW Push" ist nur teilweise implementiert und funktioniert daher noch nicht.
Der DHT22 Sensor ist noch nicht implementiert.

Für die Verwendung der Präsenztaste muss der entsprechende Parameter im BSB-lan schreibbar gesetzt werden.

Verwendung auf eigene Gefahr.

Gruß
Fabian

Schotty

Klasse, danke! Da ich selbst nur das 128x64er OLED liegen und auch keinen Zeitdruck habe, warte ich mit dem Testen noch, bis du die finale Version einstellst ;)
Handbuch zur BSB-LAN Hard- & Software (Anbindung v. Heizungsreglern, u.a. von Brötje & Elco):
https://1coderookie.github.io/BSB-LPB-LAN/

fabulous

Moin,

mit welcher Konfiguration könntest du es testen?
Dann würde ich versuchen sie nachzubilden.

Ich habe noch ein Wemos D1; und beim OLED wäre es wichtig den Chipsatz zu kennen. Es gibt da wohl verschiedene.

Gruß
Fabian

Schotty

#33
Moin,

also zum Testen hätte ich folgende Komponenten da, was hierfür in Frage käme:

- Boards: NodeMCU, WemosD1, Uno+LAN (-> EDIT: Tüddelkram, den habe ich kürzlich gerade verbaut :( )
- Display: besagtes OLED 1306 (128x64) (das ist -glaube ich- sogar auch von az-delivery; auf der Packung steht SPI OLED 1306, laut www ists wohl der SSD1306 Standardtreiber - verwendet dein 128x32er den nicht auch?)
- Gedöns: Mini-Taster hätte ich auch da, u.a. auch noch nen DHT22 

Zeitlich ist's bei mir derzeit auch knapp, aber bei entspr. schlechtem Wetter lege ich gerne eine Bastelstunde ein ;)

Gruß
Handbuch zur BSB-LAN Hard- & Software (Anbindung v. Heizungsreglern, u.a. von Brötje & Elco):
https://1coderookie.github.io/BSB-LPB-LAN/

fabulous

Moin,

hätte zwei Fragen an dich  ;D

- Hast du den DHT22 schon mal auf einem ESP-Board zum Laufen gebracht? Offensichtlich ist in der DHT-Bibliothek ein Timingfehler mit dem Resultat, dass der Sensor nur NaN liefert. Auf den Arduino- Boards läuft es mit der gleichen Bibliothek problemlos.

- Wenn du dir eine Darstellung auf dem 128x64 Display aussuchen könntest, wie sähe sie aus? Mir fehlen irgendwie die Ideen, und ich habe einfach die LCD-Darstellung übernommen. Die Schrift ist damit allerdings viel zu klein. Ich überlege daher den Text gegen aussagekräftige Symbole zu tauschen und nur die Zahlen darzustellen, aber doppelt so groß.
Hast du irgendwelche Ideen oder Wünsche?

Gruß
Fabian

Schotty

Moin Fabian,

a) bzgl DHT22@ESP: Nein, habe ich noch nicht versucht. Ich habe den lediglich rumliegen, damit ich einen zum Testen für BSB-LAN-Setups habe. Da die Teile eh nicht so genau sein sollen und auch noch recht groß sind, habe ich mich damit nie weiter auseinander gesetzt.. :(
Ich frage mich nur gerade, ob das NaN-Problem evtl mit der 3.3V Spannungsversorgung zusammenhängt, da haben nämlich kürzlich bei mir DS18B20er an einem Wemos genau so rumgezickt (es kam nur NaN zurück).
(Btw: Hast du zufällig einen BME280 rumliegen? Die laufen 1a am ESP mit den 3.3V via I2C, sind kleiner und genauer. Müsste man aber dann im Gehäuse vermutlich eine kleine Bohrung vornehmen, wo der Sensor drinsitzen könnte, damit die Werte passen..) 

b) bzgl Darstellung: Hmm, das ist ne gute Frage.. Spontan würden mir entweder nur die gängigen Symbole (Sonne, Mond, Wasserhahn etc) und/oder Abkürzungen (AT = Außentemperatur etc) einfallen.
Handbuch zur BSB-LAN Hard- & Software (Anbindung v. Heizungsreglern, u.a. von Brötje & Elco):
https://1coderookie.github.io/BSB-LPB-LAN/

Schotty

Bei den echten OneWire DS18B20 kann man die Versorgung mit 5V vornehmen und dann den PullUp zwischen DATA und einem 3.3V-Pin klemmen, somit kommt beim GPIO auch nur ein 3.3V Signal an. Soll angeblich beim DHT22 auch funktionieren, habe ich aber noch nie getestet. Kann ich gerne machen, wenns meinen ESP dann brutzelt, dann isses eben so. (Bisher waren meine ESPs auch recht 5V-kompatibel an den GPIOs, laut Datenblatt können sie das aber offiziell nicht, weshalb das also grundsätzlich nicht zu empfehlen ist..)
Handbuch zur BSB-LAN Hard- & Software (Anbindung v. Heizungsreglern, u.a. von Brötje & Elco):
https://1coderookie.github.io/BSB-LPB-LAN/

Schotty

..an einem zu kurzen Abfrageintervall des DHT22 wird's vermutlich nicht liegen, oder? Die sind wohl eher etwas 'lahm'.. Was hast du da für ein Intervall eingestellt?
Handbuch zur BSB-LAN Hard- & Software (Anbindung v. Heizungsreglern, u.a. von Brötje & Elco):
https://1coderookie.github.io/BSB-LPB-LAN/

fabulous

#38
Moin,

das Ausleseintervall sind 5s. Sollte also passen.
Ich habe mir aber jetzt auch einen BME280 bestellt. Ich möchte auf jeden Fall einen Sensor mit Feuchtigkeitsmessung, daher passen die DS nicht.

Das OLED läuft zusammen mit dem restlichen Code nicht auf dem Arduino aufgrund Speicherplatzmangels. Die Adafruit GFX Bibliothek verschlingt relativ viel Ressourcen. Vielleicht muss ich eine Alternative ausprobieren.

Ich habe auch eine Darstellung für das OLED gefunden mit der ich ganz zufrieden bin.

EDIT: ich habe einen 4.7kOhm Pull up verwendet. Leider habe ich kein Oszi um der Sache auf den Grund zu gehen.

Gruß
Fabian

Schotty

Moin,

das sieht doch gut aus! Rechts der Wasserhahn und die Flamme symbolisieren dann den Zustand, ob gerade TWW bereitet wird und/oder ob der Brenner an ist?

Bzgl PullUp:
Falls du das auf mein Geschreibsel bezogen hattest: Bitte beachte, dass ich von Versorgung mit 5V und dann PullUp zwischen DATA und einem 3.3V-Pin sprach! Also beim ESP dann nicht den PullUp zwischen 5V und DATA! Aber wie gesagt - angeblich soll das mit nem DHT22 funktionieren, getestet habe ich es noch nicht.
BME280 ist auf jeden Fall ne gute Wahl.

Bzgl Speicherplatz:
Hmm.. Es gibt für die OLEDs eine 'kleine' speicherplatzoptimierte Version: SSD1306Ascii (ArduinoIDE -> Werkzeuge -> Bibliotheken verwalten), aber das ist text-only, da wirst du wohl keine Wasserhähne finden :( - aber wäre ja evtl eine Option, wenn du Abkürzungen o.ä. nimmst?
Handbuch zur BSB-LAN Hard- & Software (Anbindung v. Heizungsreglern, u.a. von Brötje & Elco):
https://1coderookie.github.io/BSB-LPB-LAN/

fabulous

Moin,

anbei die neueste Version v0.07.

- das LCD ist rausgeflogen
- OLEDs 128x64 sowohl mit SSD1306 als auch mit SH1106 werden unterstützt
- ich verwende das 1,3 Zoll OLED. Es passt ziemlich gut in eine TAE-Dosenabdeckung. Siehe Fotos.
- TWW Push Button implementiert
- ist ein Sensor angeschlossen, werden die Sensorwerte statt RT_soll und RT_ist angezeigt.

Gruß
Fabian

-cr

#41
Danke für die Lösungsvorlage zu meiner ersten IoT-Implementierung, Fabian!
Auch wenn von Deinem Kode nur noch winzige Fragmente (und ein Icon) übrig geblieben sind, hat es mir doch sehr geholfen.

Mein Anliegen war: Protokollierung der jüngsten Aktivitäten unserer Heizung und Anzeige aller für mich interessanter Temperaturen auf einen Blick - ohne FHEM-Server oder so, nur mit BSB-LAN im Brennergehäuse im Keller und einer schlanken Anzeige-Einheit im Hausflur.

Nachgerüstet habe ich dann gleich noch:
- Möglichkeit, den Anzeigeinhalt per HTTP abzurufen
- Präsenzdarstellung für ausgewählte Computer (ok, eher Handys=Personen :) im Netz

Ein Beispiel für die Darstellung (im Zeitraffer) auf dem SSD1306 am ESP32 sowie den Quellkode füge ich unten an, falls es jemanden interessiert.
(Das Beispiel beinhaltet keine Präsenzdarstellung. Die würde mit einer Pixelzeile je Computer unten eingefügt, und die oberen Grafiken würden entsprechend verkleinert werden.)

Grüße,
Christian

P.S. Für die aktuelle Version nicht das *.zip hier nutzen sondern https://github.com/DE-cr/BSBmonCR :)

fabulous

Freut mich, dass ich helfen konnte.

Ich mag die Wassertropfen ... :-)