ich habe meinen HM-Levelsensor viewtopic.php?f=18&t=38264 auf einen Arduino NodeMCU umgerüstet. Damit bin ich von der Funkreichweite und des DC der CCU unabhängig und benötige lediglich eine WLAN-Verbindung. Desweiteren kann ich genauere Werte erfassen. Falls jemand Interesse an einem Nachbau hat, hier die Anleitung dazu.
Teileübersicht:
- NodeMCU
- Ultraschallmodul US-100 (hat bereits Temperaturkompensation onboard)
- Je nach Bedarf Stecker, Buchsen und Kabel
Der US-100 ist über die serielle Schnittstelle (Rx/Tx) angeschlossen. Damit wird die Messung nicht durch die Kabellänge verfälscht.
Über die IP-Adresse des NodeMCU kann auf die Webseite zugegriffen werden um Werte auszulesen und zu ändern.
Arduino-Code (der Temperaturwert ist rein informativ und kann auch weggelassen werden):
Code: Alles auswählen
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <RunningMedian.h>
// CONSTANTS:
const int DISTANCE_RANGE_BEGIN = 1635; // Maximale Distanz in mm (Sensor > Tankboden)
const uint32_t MEASUREMENT_PAUSE = 600;
// ******* Netzwerkeinstellungen, bitte anpassen! *******
const char* ssid = "#####"; // SSID des vorhandenen WLANs
const char* password = "#################"; // Passwort für das vorhandene WLAN
IPAddress gateway(***,***,***,***); // IP-Adresse des WLAN-Gateways MIT KOMMA
IPAddress subnet(255,255,255,0); // Subnetzmaske
IPAddress ip(***,***,***,***); // feste IP-Adresse für den NodeMCU MIT KOMMA
const char* host = "***.***.***.***"; // 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
// ******* Einstellungen fuer Meldungen an die CCU, bitte anpassen! *******
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, junk, US100temp = 0, Average = 0, Distance = 0;
RunningMedian US100distance = RunningMedian(27);
unsigned long jetztMillis = 0;
unsigned long deltaMessungMillis = deltaMessungSekunden * 1000, letzteMessungMillis = 0;
unsigned long deltaMeldungMillis = deltaMeldungSekunden * 1000, letzteMeldungMillis = 0;
String antwort = "", meldung = "",letzteMeldungCCUzeit = "";
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()
{
// WLAN-Verbindung herstellen
WiFi.config(ip, gateway, subnet); // auskommentieren, falls eine dynamische IP bezogen werden soll
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
// Verbindungsaufbau abwarten
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
}
// 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()
{
// 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();
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void messung() // Sensor abfragen
{
// Serielle Schnittstelle für US-100 öffnen
Serial.begin(9600);
delay(100);
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
{
HByte = Serial.read(); // Read both bytes
LByte = Serial.read();
Distance = (HByte * 256 + LByte);
delay(200);
}
US100distance.add(Distance);
}
Average = US100distance.getAverage(27);
level = (DISTANCE_RANGE_BEGIN - Average);
// 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)
{
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)
{
letzteMeldungCCUzeit = zeile;
}
}
letzteMeldungMillis = jetztMillis; // gemeldete Daten merken
levelCCU = level;
tempCCU = temp;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void wurzel_behandlung()// bei Aufruf des Root-Verzeichnisses
{
String betriebszeit = zeitstempel();
antwort = "WeMos Oelstandsensor\n";
antwort = antwort + "\tBetriebszeit: " + betriebszeit + " (Std:Min:Sek)\n";
antwort = antwort + "\tVerbunden mit: " + ssid + "\n";
int rssi = WiFi.RSSI();
antwort = antwort + "\tSignalstaerke: " + String(rssi) + " dBm\n\n";
antwort = antwort + "Letzte Messwerte\n\tFuellhoehe: " + String(level) + " mm\n";
antwort = antwort + "\tTemperatur: " + String(temp) + " *C\n\n";
antwort = antwort + "Letzte Datenuebertragung CCU: " + letzteMeldungCCUzeit + "\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 + "\tZeitintervall: " + String(deltaMeldungSekunden) + " Sekunden\n";
antwort = antwort + "\tFuellhoehedifferenzwert: " + String(deltaLevel) + " mm\n";
antwort = antwort + "\tTemperaturdifferenzwert: " + String(deltaTemp) + " *C\n\n";
antwort = antwort + "HTTP-Befehlsuebersicht:\n";
antwort = antwort + "\"192.168.178.72/level\" gibt die zuletzt gemessenen Fuellhoehe aus (mm)\n";
antwort = antwort + "\"192.168.178.72/temp\" gibt die zuletzt gemessene Temperatur aus (Grad Celsius)\n";
antwort = antwort + "\"192.168.178.72/zeit\" gibt den CCU-Zeitstempel aus, an dem die letzte Meldung an die CCU erfolgte\n";
antwort = antwort + "\"192.168.178.72/temp?delta=\" setzt den Temperatur-Differenzwert in *C, der eine CCU-Meldung ausloest\n";
antwort = antwort + "\"192.168.178.72/level?delta=\" setzt den Fuellhoehe-Differenzwert in mm, der eine CCU-Meldung ausloest\n";
antwort = antwort + "\"192.168.178.72/zeit?delta=\" setzt die Zeitspanne (in Sekunden), nach der spaetestens eine CCU-Meldung erfolgt\n";
antwort = antwort + "\"192.168.178.72/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
{
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
{
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 != "")
{
deltaMessungMillis = mess.toInt() * 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);
}
}
Hier noch ein Bild des fertigen Gerätes: