HM-LevelSensor: Ultraschall-Füllstandsmessung für HomeMatic

User stellen ihre Haussteuerung vor

Moderator: Co-Administratoren

wendy2702
Beiträge: 463
Registriert: 05.03.2014, 19:31
Hat sich bedankt: 1 Mal
Danksagung erhalten: 1 Mal

Re: HM-LevelSensor: Ultraschall-Füllstandsmessung für HomeMatic

Beitrag von wendy2702 » 15.08.2023, 12:43

DJDieter hat geschrieben:
14.10.2020, 21:46


Ich verwende den US-100 im UART-Mode sowohl in meinem Öltank wie auch in meiner Zisterne und hatte noch keine Probleme. Er hat auch den Vorteil der integrierten Temperaturkompensation.
HI,

vernwendest du die Messung noch und kannst mir verraten wie das mit dem UART-Mode gemeint ist und wie/ob der Sketch angepasst werden muss?

Danke
piVCCU3/iobroker mit einigen Aktoren, Sensoren, Empfängern und Sendern.

DJDieter
Beiträge: 312
Registriert: 11.01.2008, 14:41
System: Alternative CCU (auf Basis OCCU)
Hat sich bedankt: 33 Mal
Danksagung erhalten: 20 Mal

Re: HM-LevelSensor: Ultraschall-Füllstandsmessung für HomeMatic

Beitrag von DJDieter » 15.08.2023, 13:41

wendy2702 hat geschrieben:
15.08.2023, 12:43
HI,

vernwendest du die Messung noch und kannst mir verraten wie das mit dem UART-Mode gemeint ist und wie/ob der Sketch angepasst werden muss?

Danke
Ja, die Geräte laufen bei mir noch immer. Über UART wird der US-100 seriell angesprochen. Für die Distanz wird ein

Code: Alles auswählen

Serial.write(0x55); (für Temperatur: 0x50)
gesendet und der Sensor gibt die gemessene Entfernung zurück. Vorteil: der US-100 misst selber (samt Temperaturkompensation) und es entsteht keine Laufzeitverfälschung.

Der andere Weg geht über GPIO. Hier wird für eine bestimmte Zeit ein PIN auf "HIGH" gesetzt und über einen anderen dann die Zeit bis zum Echo gemessen. Je nach Länge der Kabel vom Arduino zum US-100 wird die Echo-Zeit verfälscht, da hier der Arduino die Berechnung übernimmt.

! Die Erklärung ist laienhaft, da ich kein Programmierer bin! Bitte dafür nicht prügeln.

Hier mal ein Ausschnitt meines Sketchs:

Code: Alles auswählen

unsigned int  HByte = 0, LByte = 0;
int distance;
void loop()
Serial.begin(9600); // Serielle Schnittstelle für US-100 öffnen
delay(100);
Serial.flush(); // Buffer löschen. 
Serial.write(0x55); // Messbefehl zum US-100 senden
delay(200); // Zeit für den US-100 zum Verarbeiten
 if (Serial.available() >= 2)  // mindestens 2 Byte im Buffer
    {
        HByte = Serial.read(); // Lese High-byte
        LByte = Serial.read(); // Lese Low-byte
        distance = (HByte * 256 + LByte);
    }

Code: Alles auswählen

US-100     >  Arduino
--------------------------
Trigger/Tx > Rx
Echo/Rx    > Tx
Raspberry PI 4 mit RaspberryMatic, 4 LAN-Gateways, zwei HmIP-HAP und 248 Geräte
CUxD mit 357 Kanälen auf 64 Geräten
Zusatzsoftware: XML-API, CUxD-Highcharts, NEO-Server, Programmedrucken, CUxD, E-Mail, Philips Hue, Messenger, CCU-Historian, JB-HP-Devices, HomeKit HomeMatic
Anbindungen: Wolf eBus; NodeMCU-Ultraschall-Füllstandsmessung mit Temperatureinfluß; Fußbodenheizung mit Rücklauftemperaturbegrenzer (RTL)

wendy2702
Beiträge: 463
Registriert: 05.03.2014, 19:31
Hat sich bedankt: 1 Mal
Danksagung erhalten: 1 Mal

Re: HM-LevelSensor: Ultraschall-Füllstandsmessung für HomeMatic

Beitrag von wendy2702 » 15.08.2023, 13:49

OK. Danke für die Antwort.

Du würdest nicht zufällig den Vollständigen Sketch zur Verfügung stellen?

Verwendest du den Sensor auch in einer Zisterne? Wie sieht die Langzeiterfahrung heute bezüglich der Feuchtigkeit aus?
piVCCU3/iobroker mit einigen Aktoren, Sensoren, Empfängern und Sendern.

DJDieter
Beiträge: 312
Registriert: 11.01.2008, 14:41
System: Alternative CCU (auf Basis OCCU)
Hat sich bedankt: 33 Mal
Danksagung erhalten: 20 Mal

Re: HM-LevelSensor: Ultraschall-Füllstandsmessung für HomeMatic

Beitrag von DJDieter » 15.08.2023, 13:58

wendy2702 hat geschrieben:
15.08.2023, 13:49
Verwendest du den Sensor auch in einer Zisterne? Wie sieht die Langzeiterfahrung heute bezüglich der Feuchtigkeit aus?
Läuft seit drei Jahren ohne Probleme.
Du würdest nicht zufällig den Vollständigen Sketch zur Verfügung stellen?
Klar. Ich hab jedoch zwei verschiedene. Einen für einen WLAN-Arduino und einen für das Funk-Sendemodul HM-MOD-EM-8Bit. Welchen brauchst Du?
Raspberry PI 4 mit RaspberryMatic, 4 LAN-Gateways, zwei HmIP-HAP und 248 Geräte
CUxD mit 357 Kanälen auf 64 Geräten
Zusatzsoftware: XML-API, CUxD-Highcharts, NEO-Server, Programmedrucken, CUxD, E-Mail, Philips Hue, Messenger, CCU-Historian, JB-HP-Devices, HomeKit HomeMatic
Anbindungen: Wolf eBus; NodeMCU-Ultraschall-Füllstandsmessung mit Temperatureinfluß; Fußbodenheizung mit Rücklauftemperaturbegrenzer (RTL)

wendy2702
Beiträge: 463
Registriert: 05.03.2014, 19:31
Hat sich bedankt: 1 Mal
Danksagung erhalten: 1 Mal

Re: HM-LevelSensor: Ultraschall-Füllstandsmessung für HomeMatic

Beitrag von wendy2702 » 15.08.2023, 14:03

Ich würde glatt beide nehmen und bei Gelegenheit wahrscheinlich auf die WLAN Version wechseln. :D
piVCCU3/iobroker mit einigen Aktoren, Sensoren, Empfängern und Sendern.

DJDieter
Beiträge: 312
Registriert: 11.01.2008, 14:41
System: Alternative CCU (auf Basis OCCU)
Hat sich bedankt: 33 Mal
Danksagung erhalten: 20 Mal

Re: HM-LevelSensor: Ultraschall-Füllstandsmessung für HomeMatic

Beitrag von DJDieter » 15.08.2023, 14:18

wendy2702 hat geschrieben:
15.08.2023, 14:03
Ich würde glatt beide nehmen und bei Gelegenheit wahrscheinlich auf die WLAN Version wechseln. :D
Die Sketche wurden von mir teilweise stark modifiziert (OTA-Update, Zeitserver, Watchdog, usw.). Einfach mal durcharbeiten und unnötiges entfernen.
Für ESP:

Code: Alles auswählen

//#define Serialprint

// Configuration of NTP
#define NTP_SERVER "ptbtime2.ptb.de"
#define TimeZone "CET-1CEST,M3.5.0/02,M10.5.0/03"

String vers = "1.1";
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <RunningMedian.h>
#include <ArduinoOTA.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <AddrList.h>
#include <time.h>                   // time() ctime()

time_t now;                         // this is the epoch
tm tm;                              // the structure tm holds time information in a more convient way

String datum = (__DATE__);
String zeit = (__TIME__);
String file = (__FILE__);
String dat = (datum+" - "+zeit);
String linkLocal, ipv6, ipv4, stamp, stampNow;

// CONSTANTS:
const int DISTANCE_RANGE_BEGIN = 1694; // Maximale Distanz in mm (Sensor > Tankboden)

// ******* Netzwerkeinstellungen *******
const char* ssid = ""; // SSID des vorhandenen WLANs
const char* password = ""; // Passwort für das vorhandene WLAN
IPAddress gateway(192,xxx,xxx,x); // IP-Adresse des WLAN-Gateways
IPAddress subnet(255,255,255,0); // Subnetzmaske
IPAddress ip(192,xxx,xxx,x); // feste IP-Adresse für den WeMos
IPAddress dns(192,xxx,xxx,x);
const char* host = "192.xxx.xxx.x"; // IP-Adresse der CCU (mit Punkten!)
ESP8266WebServer server(80); // Webserver initialisieren auf Port 80

// ******* Sensoreinstellungen *******
unsigned long deltaMessungSekunden = 10; //Zeitintervall (Sekunden) nach dem eine Messung erfolgt
int korrLevel = 0; // Korrekturwert fuer die Ölstandmessung
int korrTemp = 0; // Korrekturwert fuer die Temperaturmessung

// ******* Einstellungen fuer Meldungen an die CCU *******
String levelCCUname = "CUxD.CUX9000018:1.SET_STATE"; // CUxD-Gerät "Ölstand"
String tempCCUname = "Tanktemperatur"; // Bezeichnung der CCU-Systemvariable für die gemessene Temperatur
unsigned long deltaMeldungSekunden = 600; // Zeitintervall (Sekunden) nach dem eine CCU-Meldung erfolgt (0 bedeutet nie)
int deltaLevel = 1; // Füllhöheänderung bei der eine CCU-Meldung erfolgt (0 bedeutet nie)
int deltaTemp = 1; // Temperaturaenderung (°C) bei der eine CCU-Meldung erfolgt (0 bedeutet nie)

// US-100 ultrasonic rangefinder:
unsigned int  HByte = 0, LByte = 0;
int level = 0, levelCCU = 0, temp = 0, tempCCU = 0, US100temp = 0, lastDistance = 0;
RunningMedian samplesMed = RunningMedian(5);
RunningMedian samplesAvg = RunningMedian(5);

unsigned long jetztMillis = 0;
unsigned long wifi_disc = 0;
unsigned long deltaMessungMillis = deltaMessungSekunden * 1000, letzteMessungMillis = 0;
unsigned long deltaMeldungMillis = deltaMeldungSekunden * 1000, letzteMeldungMillis = 0;
String antwort = "", meldung = "",letzteMeldungCCUzeit = "";
unsigned long previousMillis = 0;
int ledState;
unsigned long check_wifi = 30000;

String zeitstempel()// Betriebszeit als Stunde:Minute:Sekunde
{
  char stempel[10];
  int lfdStunden = millis()/3600000;
  int lfdMinuten = millis()/60000-lfdStunden*60;
  int lfdSekunden = millis()/1000-lfdStunden*3600-lfdMinuten*60;
  sprintf (stempel,"%03d:%02d:%02d", lfdStunden, lfdMinuten, lfdSekunden);
  return stempel;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup()
{
  ESP.wdtDisable();
// Seriellen Monitor für Kontrollausgaben öffnen
  Serial.begin(9600);
  Serial.println("");
  Serial.println("WeMos Oelstandsensor");
  WiFi.persistent(false);
  delay(100);
  pinMode(LED_BUILTIN,OUTPUT);

  configTime(TimeZone, NTP_SERVER); 
  
// WLAN-Verbindung herstellen
  WiFi.config(ip, gateway, subnet, dns); // auskommentieren, falls eine dynamische IP bezogen werden soll
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  pinMode(LED_BUILTIN,OUTPUT);
// Verbindungsaufbau abwarten
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nconnected IPv4\n");
  
ipv6config();

// Port (Default: 8266)
// ArduinoOTA.setPort(8266);

// Hostname (Default: esp8266-[ChipID])
ArduinoOTA.setHostname("Heizoelstand");

ArduinoOTA.onStart([]()
{
  String type;
  if (ArduinoOTA.getCommand() == U_FLASH)
  {
    type = "sketch";
  } else { // U_FS
    type = "filesystem";
  }

  // NOTE: if updating FS this would be the place to unmount FS using FS.end()
  Serial.println("Start updating " + type);
});
ArduinoOTA.onEnd([]()
{
  Serial.println("\nEnd");
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total)
{
  Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
});
ArduinoOTA.onError([](ota_error_t error)
{
  Serial.printf("Error[%u]: ", error);
  if (error == OTA_AUTH_ERROR)
  {
    Serial.println("Auth Failed");
  } else if (error == OTA_BEGIN_ERROR)
  {
    Serial.println("Begin Failed");
  } else if (error == OTA_CONNECT_ERROR)
  {
    Serial.println("Connect Failed");
  } else if (error == OTA_RECEIVE_ERROR)
  {
    Serial.println("Receive Failed");
  } else if (error == OTA_END_ERROR)
  {
    Serial.println("End Failed");
  }
});
ArduinoOTA.begin();
Serial.println("Ready");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());

// HTTP-Anfragen bearbeiten
  server.on("/", wurzel_behandlung);
  server.on("/level", melde_level);
  server.on("/zeit", melde_zeit);
  
// HTTP-Server starten
  server.begin();

// Startwerte fuer Zeittrigger
  letzteMessungMillis = millis();
  letzteMeldungMillis = millis();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop()
{
  ArduinoOTA.handle();
  if(WiFi.status() == WL_CONNECTED)
  {
    led(1000);
  }
  else
  {
    led(100);
  }
// auf HTTP-Anfragen warten
  server.handleClient();

  jetztMillis = millis();

// neue Messung falls Zeitintervall erreicht
  if(jetztMillis - letzteMessungMillis > deltaMessungMillis)
  {
    messung();
  }

// neue Meldung an die CCU falls Zeitintervall erreicht
  if(!deltaMeldungMillis == 0 && jetztMillis - letzteMeldungMillis > deltaMeldungMillis)
  {
    melde_CCU();
  }

// neue Meldung an die CCU falls Ölstandänderung den Schwellwert erreicht
  if(!deltaLevel == 0 && abs(level - levelCCU) >= deltaLevel)
  {
    melde_CCU();
  }
  
// neue Meldung an die CCU falls Temperaturaenderung den Schwellwert erreicht
  if(!deltaTemp == 0 && abs(temp - tempCCU) >= deltaTemp) // Neue Meldung wg. Temperaturaenderung
  {
    melde_CCU();
  }
// WiFi-Kontrolle
  if((WiFi.status() != WL_CONNECTED)&& (millis() > check_wifi))
  {
    wifi_disc = millis();
    wifiReconnect();
  }
  if (wifi_disc < 10000)
  {
  ESP.wdtFeed();
  }
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void messung() // Sensor abfragen
{
  // Serielle Schnittstelle für US-100 öffnen
  Serial.begin(9600);
  delay(100);

  samplesAvg.clear();
  
for (int avgloop = 0; avgloop < 5; avgloop++)
{
  ESP.wdtFeed();
  samplesMed.clear();
  for (int medloop = 0; medloop < 5; medloop++)
  {
    ESP.wdtFeed();
    Serial.flush(); // Clear the serial1 buffer. 
      while (Serial.available() >= 1)  // seemed like flush() was not working so I added this.
       { 
       int junk = Serial.read();
       }
   Serial.write(0x55); // Send a "distance measure" command to US-100
   delay(200); // US100 response time depends on distance.
   if (Serial.available() >= 2)  // at least 2 bytes are in buffer
    {
        HByte = Serial.read(); // Read both bytes
        LByte = Serial.read();
        int distance = (HByte * 256 + LByte);
        samplesMed.add(distance);
    }
  }
  int avrg = samplesMed.getMedian();
  samplesAvg.add(avrg);
}

int Distance = samplesAvg.getAverage();

level = (DISTANCE_RANGE_BEGIN + korrLevel - Distance);

// Read temperature from the US-100 ultrasonic rangefinder's temp sensor at the top of the tank. The tank air heats up in the sun.
  Serial.flush(); 
   while (Serial.available() >= 1)  // seemed like flush() was not working so I added this.
   { 
       int junk = Serial.read();
   }
    Serial.write(0x50); // send command to request temperature byte.
    delay(50); // temp response takes about 2ms after command ends.
    if (Serial.available() >= 1) 
    {
        US100temp = Serial.read();
        if ((US100temp > 1) && (US100temp < 130)) 
        {
           US100temp -= 45; // Correct by the 45 degree offset of the US100. 
        }
    }
//    Serial.end();
  temp = US100temp + korrTemp;
  letzteMessungMillis = jetztMillis;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void melde_CCU()// Werte an die CCU melden
  {
  WiFiClient client; // Webclient initialisieren
  const int httpPort = 8181;
  if (!client.connect(host, httpPort)) // mit dem CCU-Port 8181 verbinden
  {
     delay(100);
    return;
  }
  String url = "/xy.exe?antwort1=dom.GetObject('" + levelCCUname + "').State('" + level + "')"
  "&antwort2=dom.GetObject('" + tempCCUname + "').State('" + temp + "')";
  client.println(String("GET ") + url + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n"); // Daten an CCU melden
  delay(100);
  
  int i = 0;
  while(client.available()) // Antwort der CCU zeilenweise auslesen
    {
    i ++;
    String zeile = client.readStringUntil('\r'); // Zeitstempel der CCU ausfiltern und merken
    if (i == 7)
    {
      String stamp = NtpTime();
      stampNow = stamp;
    }
  }
  letzteMeldungMillis = jetztMillis; // gemeldete Daten merken
  levelCCU = level;
  tempCCU = temp;
}   
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void wurzel_behandlung()// bei Aufruf des Root-Verzeichnisses
{
  ipv6config();
  String stamp = NtpTime();
  String betriebszeit = zeitstempel();
  antwort = "WeMos Oelstandsensor\n";
  antwort = antwort + "\t" +file + " - Version: " + vers + "\n";
  antwort = antwort + "\tUpdate: " + dat + "\n";
  antwort = antwort + "\tBetriebszeit: " + betriebszeit + " (Std:Min:Sek)\n";
  antwort = antwort + "\tUhr: " + stamp + "\n";
  antwort = antwort + "\tVerbunden mit: " + ssid + "\n";
  int rssi = WiFi.RSSI();
  antwort = antwort + "\tSignalstaerke: " + String(rssi) + " dBm\n";
  antwort = antwort + "\tIPv4-Adresse: http://" + ipv4 + "\n";
  antwort = antwort + "\tIPv6-Global:  http://[" + ipv6 + "]" + "\n";
  antwort = antwort + "\tIPv6-Local:   http://[" + linkLocal + "]" + "\n\n";
  antwort = antwort + "Letzte Messwerte\n\tMessintervall: " + String(deltaMessungSekunden) + " Sekunden\n";
  antwort = antwort + "\tFuellhoehe: " + String(level) + " mm\n";
  antwort = antwort + "\tTemperatur: " + String(temp) + " *C\n";
  antwort = antwort + "Korrekturwerte\n\tSensorabstand: " + String(korrLevel) + " mm\n";
  antwort = antwort + "\tTemperatur: " + String(korrTemp) + " *C\n\n";
  antwort = antwort + "Letzte Datenuebertragung CCU\n\t" + stampNow + "\n";
  antwort = antwort + "\tGemeldete Fuellhoehe: " + String(levelCCU) + " mm\n";
  antwort = antwort + "\tGemeldete Temperatur: " + String(tempCCU) + " *C\n\n";
  antwort = antwort + "Ausloeser fuer Datenuebertragung CCU\n";
  antwort = antwort + "\tSendeintervall: " + String(deltaMeldungSekunden) + " Sekunden\n";
  antwort = antwort + "\tFuellhoehendifferenzwert: " + String(deltaLevel) + " mm\n";
  antwort = antwort + "\tTemperaturdifferenzwert: " + String(deltaTemp) + " *C\n\n";
  antwort = antwort + "HTTP-Befehlsuebersicht:\n";
  antwort = antwort + "\"192.xxx.xxx.x/level\"           gibt die zuletzt gemessenen Fuellhoehe aus (mm)\n";
  antwort = antwort + "\"192.xxx.xxx.x/temp\"            gibt die zuletzt gemessene Temperatur aus (Grad Celsius)\n";
  antwort = antwort + "\"192.xxx.xxx.x/zeit\"            gibt den CCU-Zeitstempel aus, an dem die letzte Meldung an die CCU erfolgte\n";
  antwort = antwort + "\"192.xxx.xxx.x/temp?delta=\"     setzt den Temperatur-Differenzwert in *C, der eine CCU-Meldung ausloest\n";
  antwort = antwort + "\"192.xxx.xxx.x/temp?korr=\"      setzt den Korrekturwert fuer die Temperaturmessung in *C\n";
  antwort = antwort + "\"192.xxx.xxx.x/level?delta=\"    setzt den Fuellhoehe-Differenzwert in mm, der eine CCU-Meldung ausloest\n";
  antwort = antwort + "\"192.xxx.xxx.x/level?korr=\"     setzt den Korrekturwert fuer Abstand Tankboden > Sensor in mm\n";
  antwort = antwort + "\"192.xxx.xxx.x/zeit?delta=\"     setzt die Zeitspanne (in Sekunden), nach der spaetestens eine CCU-Meldung erfolgt\n";
  antwort = antwort + "\"192.xxx.xxx.x/zeit?mess=\"      definiert das Messintervall (in Sekunden)\n";
  server.send(300, "text/plain", antwort);
  delay(150);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void melde_level() // bei Aufruf von ".../level"
{
  String delta = server.arg("delta");
  String korr = server.arg("korr");
  if (delta != "")
  {
    deltaLevel = delta.toFloat();
    server.send(200, "text/plain", "Fuellhoehedifferenzwert fuer CCU-Meldungen auf " + delta + " mm gesetzt.");
    delay(100);
  }
  else if (korr != "")
  {
    korrLevel = korr.toFloat();
    server.send(200, "text/plain", "Korrekturwert fuer Abstand Tankboden > Sensor auf " + korr + " mm gesetzt.");
    delay(100);
  }
  else {
    server.send(200, "text/plain", String(level));
    delay(100);
  }
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void melde_temp() // bei Aufruf von ".../temp"
{
  String delta = server.arg("delta");
  String korr = server.arg("korr");
  if (delta != "")
  {
    deltaTemp = delta.toFloat();
    server.send(200, "text/plain", "Temperaturdifferenzwert fuer CCU-Meldungen auf " + delta + " *C gesetzt.");
    delay(100);
  }
  else if (korr != "")
  {
    korrTemp = korr.toFloat();
    server.send(200, "text/plain", "Korrekturwert fuer Temperaturmessung auf " + korr + " *C gesetzt.");
    delay(100);
  }
  else
  {
    server.send(200, "text/plain", String(temp));
    delay(100);
  }
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void melde_zeit()// bei Aufruf von ".../zeit"
  {
  String delta = server.arg("delta");
  String mess = server.arg("mess");
  if (delta != "")
  {
    deltaMeldungSekunden = delta.toInt();
    deltaMeldungMillis = deltaMeldungSekunden * 1000;
    server.send(200, "text/plain", "Zeitintervall fuer CCU-Meldungen auf " + delta + " Sekunden gesetzt.");
    delay(100);
  }
  else if (mess != "")
  {
    deltaMessungSekunden = mess.toInt();
    deltaMessungMillis = deltaMessungSekunden * 1000;
    server.send(200, "text/plain", "Zeitintervall fuer Sensorabfrage auf " + mess + " Sekunden gesetzt.");
    delay(100);
  }
  else
  {
    server.send(200, "text/plain", "Letzte Aktualisierung der CCU\n" + letzteMeldungCCUzeit);
    delay(100);
  }
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void wifiReconnect()
{
#ifdef Serialprint
  Serial.println("WiFi-Reconnect");
#endif
//  WiFi.config(ip, gateway, subnet); // auskommentieren, falls eine dynamische IP bezogen werden soll
//  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  WiFi.begin(ssid, password);
//  Serial.print("Verbindungsaufbau");
  check_wifi = millis() + 30000;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void led(unsigned long interval)
{
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval)
  {
    previousMillis = currentMillis; // save the last time you blinked the LED

// if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
    {
      ledState = HIGH;
    }
    else
    {
      ledState = LOW;
    }
    digitalWrite(LED_BUILTIN, ledState); // set the LED with the ledState of the variable:
  }
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
String NtpTime()
{
  String SZ;
  time(&now);                       // read the current time
  localtime_r(&now, &tm);           // update the structure tm with the current time
/*  Serial.print("year:");
  Serial.print(tm.tm_year + 1900);  // years since 1900
  Serial.print("\tmonth:");
  Serial.print(tm.tm_mon + 1);      // January = 0 (!)
  Serial.print("\tday:");
  Serial.print(tm.tm_mday);         // day
  Serial.print("\thour:");
  Serial.print(tm.tm_hour);         // hour 0-23
  Serial.print("\tmin:");
  Serial.print(tm.tm_min);          // minutes 0-59
  Serial.print("\tsec:");
  Serial.print(tm.tm_sec);          // seconds 0-61*
  Serial.print("\twday");
  Serial.print(tm.tm_wday);         // days since Sunday 0-6
  Serial.print(tm.tm_isdst);        // 1 bei MESZ, sonst MEZ*/
  
  String tag = String(tm.tm_mday);
  String monat = String(tm.tm_mon + 1);
  int jahre = (tm.tm_year + 1900);
  String jahr = String(jahre);
  String stunde = String(tm.tm_hour);
  String minut = String(tm.tm_min);
  String sekunde = String(tm.tm_sec);
  if (tm.tm_isdst == 1)
  SZ = ("[MESZ]");
  else
  SZ = ("[MEZ]");
  stamp = (tag + '.' + monat + '.' + jahr + ' ' + '-' + ' ' + stunde + ':' + minut + ':' + sekunde + ' ' + SZ);
  return stamp;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ipv6config()
{
#if LWIP_IPV6
// Warten auf die Globale IPv6
  for (bool configured = false; !configured;)
  {
    for (auto addr : addrList)
      if (configured = addr.isV6() && !addr.isLocal())
      {
        break;
      }
    Serial.print('.');
    delay(500);
  }
  Serial.println("\nconnected IPv6\n");
  for (auto a : addrList)
  {
    a.isV6() ? a.isLocal() ? linkLocal = a.toString() : ipv6 = a.toString() : ipv4 = a.toString();
  }
#endif
}
Für HM-MOD-EM-8Bit:

Code: Alles auswählen

// Libraries to include:
#include <RunningMedian.h>  // by  Rob.Tillaart at gmail.com

// CONSTANTS:
const int DISTANCE_RANGE_BEGIN = 1635; // Maximale Distanz in mm (Tankboden)
const int DISTANCE_RANGE_END = 80; // Minimale Distanz in mm (maximaler Füllstand)
const uint32_t MEASUREMENT_PAUSE = 600;
const uint8_t OUT_RANGE_MIN = 0; // output start of range (8-bit)
const uint8_t OUT_RANGE_MAX = 254; // output end of range (OUT_RANGE_MAX must be greater than OUT_RANGE_MIN) (8-bit)

// Variables:
int    difference = 0; // variable to hold temporary info during calculations
int    q; // for loop counters.

// US-100 ultrasonic rangefinder:
 unsigned int  MSByte = 0;
 unsigned int  LSByte = 0;
 unsigned int  mmDistance = 0;
 int           Median_mm = 0;                // Some of these I tried to use unsigned int and got an "ambiguous" compile error.
 int           TempmmDistance = 0;  //Temporärer Speicher für die Mittelwertberechnung
 int           US100tempData = 0;
 int           junk;
 RunningMedian US100reading = RunningMedian(9);

void send(uint8_t meas)
{
  PORTB = (PORTB & 0b11100000) | (meas & 0b00011111);
  PORTD = (PORTD & 0b00011111) | (meas & 0b11100000);
}

void blinkLed()
{
  for (int idx = 0; idx < 9; ++idx)
  {
    digitalWrite(LED_BUILTIN, LOW); delay(100);
    digitalWrite(LED_BUILTIN, HIGH); delay(100);
  }
  digitalWrite(LED_BUILTIN, LOW);
}
  
 // SETUP ______________________________________________________________________________________________

void setup()
{
  delay(5000);
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
// HomeMatic 8-bit transmitter; Set PB0 - PB4 and PD5 - PD7 to output
  DDRB |= 0b00011111;
  DDRD |= 0b11100000;
}

// MAIN LOOP _________________________________________________________________________________________________

void loop()
{
  mmDistance  = 0;
  int DataToAvg = 9;
  for (int avgloop = 1; avgloop < (DataToAvg + 1); avgloop++)
  {
   Serial.flush(); // Clear the serial1 buffer. 
   Serial.write(0x55); // Send a "distance measure" command to US-100
   delay(200); // US100 response time depends on distance.
   if (Serial.available() >= 2)  // at least 2 bytes are in buffer
    {
        MSByte = Serial.read(); // Read both bytes
        LSByte = Serial.read();//
        TempmmDistance = (MSByte * 256 + LSByte);
        delay(200);
        mmDistance  = mmDistance + TempmmDistance; // calculate distance in mm. Add to running sum.
        if ((TempmmDistance > DISTANCE_RANGE_END) && (TempmmDistance < DISTANCE_RANGE_BEGIN))   // Test that the distance is in range.
         {
          US100reading.add(TempmmDistance); // put another datum into the buffer for a running median.
         } else    avgloop--; // discard this datum.
    } 
  }
  mmDistance = mmDistance/DataToAvg; // calculate the mean of N measurements.
  Median_mm = US100reading.getMedian(); // get the current running median value of mm from sensor to surface of oil.
  int  Level = (DISTANCE_RANGE_BEGIN - Median_mm);
  uint8_t  measure = map(Level , 0 , 1600 , 0 , 254);

// measure and send
  uint8_t meas = measure;

  if(measure < 255)
  {
    send(meas);
  }
  else
  {
  blinkLed();
  }

// Read temperature from the US-100 ultrasonic rangefinder's temp sensor at the top of the tank. The tank air heats up in the sun.
	Serial.flush(); 
	 while (Serial.available() >= 1)  // seemed like flush() was not working so I added this.
	 { 
	     junk = Serial.read();
	 }
    Serial.write(0x50); // send command to request temperature byte.
    delay(50); // temp response takes about 2ms after command ends.
    if (Serial.available() >= 1) 
    {
        US100tempData = Serial.read(); 
        if ((US100tempData > 1) && (US100tempData < 130)) 
        {
            US100tempData -= 45; // Correct by the 45 degree offset of the US100. 
        }
    }

// pause for next measurement
  delay(MEASUREMENT_PAUSE * 1000);
}
Raspberry PI 4 mit RaspberryMatic, 4 LAN-Gateways, zwei HmIP-HAP und 248 Geräte
CUxD mit 357 Kanälen auf 64 Geräten
Zusatzsoftware: XML-API, CUxD-Highcharts, NEO-Server, Programmedrucken, CUxD, E-Mail, Philips Hue, Messenger, CCU-Historian, JB-HP-Devices, HomeKit HomeMatic
Anbindungen: Wolf eBus; NodeMCU-Ultraschall-Füllstandsmessung mit Temperatureinfluß; Fußbodenheizung mit Rücklauftemperaturbegrenzer (RTL)

wendy2702
Beiträge: 463
Registriert: 05.03.2014, 19:31
Hat sich bedankt: 1 Mal
Danksagung erhalten: 1 Mal

Re: HM-LevelSensor: Ultraschall-Füllstandsmessung für HomeMatic

Beitrag von wendy2702 » 16.08.2023, 11:05

Hi,

Sorry das ich nochmal störe aber da das mein einziges Projekt mit Arduini ist stehe ich gerade auf dem Schlauch.

Ist der Sketch für das HM Modul komplett? Wenn ja welche PINs werden verwendet?

Im Original Sketch kann ich das sehen.

Aktuell erhalte ich immer nur einen Füllstand von 71 Litern angezeigt und die TX LED am Nano blinkt eine zeitlang ganz schwach.

Danke für die Hilfe.
piVCCU3/iobroker mit einigen Aktoren, Sensoren, Empfängern und Sendern.

DJDieter
Beiträge: 312
Registriert: 11.01.2008, 14:41
System: Alternative CCU (auf Basis OCCU)
Hat sich bedankt: 33 Mal
Danksagung erhalten: 20 Mal

Re: HM-LevelSensor: Ultraschall-Füllstandsmessung für HomeMatic

Beitrag von DJDieter » 16.08.2023, 11:13

Der sollte komplett sein. Beide Sketche verwenden UART (serielle Übertragung).
Raspberry PI 4 mit RaspberryMatic, 4 LAN-Gateways, zwei HmIP-HAP und 248 Geräte
CUxD mit 357 Kanälen auf 64 Geräten
Zusatzsoftware: XML-API, CUxD-Highcharts, NEO-Server, Programmedrucken, CUxD, E-Mail, Philips Hue, Messenger, CCU-Historian, JB-HP-Devices, HomeKit HomeMatic
Anbindungen: Wolf eBus; NodeMCU-Ultraschall-Füllstandsmessung mit Temperatureinfluß; Fußbodenheizung mit Rücklauftemperaturbegrenzer (RTL)

wendy2702
Beiträge: 463
Registriert: 05.03.2014, 19:31
Hat sich bedankt: 1 Mal
Danksagung erhalten: 1 Mal

Re: HM-LevelSensor: Ultraschall-Füllstandsmessung für HomeMatic

Beitrag von wendy2702 » 16.08.2023, 12:59

OK.

Danke. Mein Fehler. Kaum nimmt man die richtigen PINs schon funktioniert es.

Das einzige was mir auffällt das zwischendurch immer mal wieder ein "0" beim Füllstand angezeigt wird.

Ist das ein bekanntes Problem?
piVCCU3/iobroker mit einigen Aktoren, Sensoren, Empfängern und Sendern.

Antworten

Zurück zu „Projektvorstellungen“