Blackjack- und Gegenleckschutz

Grüße. Es gibt so etwas - Hydrolock \ Neptun \ Avkvastorozh - Wasserabsperrsysteme, wenn ein unkontrolliertes Leck auftritt. Das Prinzip ist einfach - ein Wassersensor + Automatisierung + ein Paar elektrische Wasserhähne. Aber der Teufel steckt wie immer im Detail: wie die Wasserhähne angeordnet sind, wie die Lecksensoren angeordnet sind und warum einer 50 Rubel und der andere 500 Rubel kostet. Ein Kilogramm eines Layout-Bulletins wird um diese ganze Sache gewickelt, die Verpackung wird Ihnen die Augen ausschließen usw.

In der Geschichte werde ich durch die Bausteine ​​des Systems gehen, die mich bei der Wahl geführt haben. Das gesamte System basiert auf werkseitigen Sensoren und einem hausgemachten Controller auf der Basis von Particle (ex.Spark) Photon (z. B. einem esp8266 mit einer Cloud-IDE für die sofort einsatzbereite Verkabelung). Die Gerätebasis besteht aus einem stm-Controller und einem WLAN-Modul von Broadcom. All dies ist an einen Openhab-Server auf Orange Pi One gebunden.



Warum nicht ein fertiges System?

- Weil ich es selbst kann und es hoch ist
- Die Integration mit externen Systemen ist in vorgefertigten Systemen lahm.
- Fertige Systeme haben keine Zusatzfunktionen - unter Berücksichtigung von Zählerständen, Wassertemperatursensoren, Benachrichtigung über Wasserausfälle und anderen erotischen Fantasien beim Gehen.

Beginnen wir mit Kränen


Wählte dumm in der Stirn in Bezug auf das Drehmoment. Für einige Zeit lebte er in den Vororten, wo die Wasserqualität (wie wahrscheinlich überall in Zamkadye) zu wünschen übrig lässt. Also Kugelhähne 1/2 Zoll, wenn Sie das Jahr nicht berühren - es ist sehr schwierig zu drehen. Und auf dem beheizten 1-Zoll-Handtuchhalter versuche ich nicht einmal, ihn zu bewegen - nur wenn ich die Schulter mit einem Schraubenschlüssel verstärke, aber hier können Sie etwas abreißen. Das Problem liegt in Ablagerungen von Kalzium-Hartholz, die mit einem Wort "überwachsen" sind.

Dementsprechend fiel die Wahl auf die Profiserie aus dem Hydrolock - 21N * m Drehmoment fühlt sich nicht wie ein Werbegespräch an, der Kran ist einfach riesig - bewerten Sie den Ort seiner Installation vor dem Kauf.



Der Hahn ist abgedichtet, eine Gummidichtung um den Umfang, der Eingang unter der Verschraubung.
Entfernen Sie die Abdeckung.



Vor uns liegt die Oberseite des Brettes und der Schrittmotor. All dies wird mit 12 Volt betrieben. Durch Kurzschließen des Steuerkabels mit Masse wird das Ventil in die geschlossene Position gebracht. Auf der Platine sehen wir einen einfachen PIC 12f629 Controller. Lebte die Steuerung im Kranantrieb.

Die Rückseite der Tafel ist die interessanteste.



L293 Shagovik-Treiber und Fotokoppler (Emitter + Fotodetektor). Sie schaut auf das Hauptzahnrad des Antriebs, das in Teilen lackiert ist - weiß und schwarz, geschlossen / offen.



Der Kran dreht sich die ganze Zeit in eine Richtung, die Logik der Steuerung ist einfach - wir drehen die Welle, bis wir auf die gewünschte Farbe wechseln. Die Drehung des Krans in eine Richtung ist weniger Verschleiß und es ist weniger wahrscheinlich, dass die berührungslose Methode zur Positionsbestimmung einen variablen Widerstand oder Endschalter sauer macht / nicht funktioniert.

Zur Installation können Sie den Kran vom Antrieb abschrauben - er wird auf 2 Muttern gehalten. Zwischen dem Antrieb und dem Kran befindet sich eine wärmeisolierende Dichtung.



Ich hatte die Reparatur vor anderthalb Jahren. Der vor drei Jahren gekaufte Kran - zerlegen, hineinschauen, mehr kaufen und während der Reparatur aufwickeln. Ja, jetzt ... das Maximum, das ich in diesem höllischen Zirkus geschafft habe, war, einen Schmutzsammler in die Montage der Wasserversorgung zu legen, mit der Aussicht, ihn durch einen Kran zu ersetzen.
Und erst nach anderthalb Jahren kaufte ich einen zweiten Kran und schraubte ihn fest.

Infolgedessen beobachten wir ein seltsames und seltenes Phänomen (gelesen mit der Stimme von Drozdov) - alle Informationen von der Website des Herstellers wurden bestätigt. Darüber hinaus ist die Beschreibung eigenartig, als ob die Technikfreaks geschrieben hätten, und dann wurde das Marketing für die Leute bewässert, aber immer noch verstehen nur wenige Leute alle Chips. Es gibt nicht genügend Abschnitte auf der Website - für Integratoren mit technischen Details. Selbst auf Kosten eines erhöhten Drehmoments lagen sie nicht am Start - der Kran am Start schlägt mit einem Motor von 1,5 A und beginnt nach 2-3 Sekunden im normalen Modus (aktuell 0,7 A) zu steigen. Das Schließen dauert etwa 25 bis 30 Sekunden.

Eine andere Erfahrung: Auf Kosten des Drehmoments - es ist zu viel Zeit für Moskau, hier ist das Wasser ganz in Ordnung, anderthalb Jahre lang gibt es in einem 100-μm-Filter ein Paar Krätze und kein Überwachsen. Das große Drehmoment muss man mit dem Preis, der Öffnungszeit und dem Platz im Schrank bezahlen. Ich denke, es wird genug konventionelle Laufwerke von Hydrolock Ultimate, Neptune oder Aquastorozh geben. Ich kann nicht für die letzten beiden bürgen - ich habe es nicht geschafft, vor ungefähr 5 Jahren hatten sie teilweise Plastikzahnräder, jetzt scheinen sie es repariert zu haben.

Es gibt auch einen Winner-Hydrolock mit direktem Anschluss von Sensoren an das Laufwerk - wenn Sie nicht alles brauchen, was ich getan habe. Dort ist die Stromversorgung unabhängig von 4 Batterien und die Basis ähnelt einem ultimativen Antrieb. Im Allgemeinen ist es möglicherweise auch für einen selbstgebauten Controller interessant - es ist 5 Volt, Sie müssen nicht zwei Busse auf 5 und 12 Volt setzen und Sie können die optische Isolation wegwerfen.

Lecksensoren


Ich habe die Sensoren des gleichen WSU-Zählers gekauft - universell. Sie haben zwei „Open Collector“ -Ausgänge, einer zieht nur dann auf den Boden, wenn Wasser vorhanden ist, der zweite - wenn Wasser eindringt, zieht es die ganze Zeit auf den Boden, bis die Stromversorgung unterbrochen wird. Ich verwende nur den ersten Ausgang, der Rest der Logik befindet sich im Controller, aber es sieht so aus, als ob dieser Ausgang für einige weitere Condo-Versandsysteme nützlich sein kann.

Die Drähte im Kit sind irgendwo drei Meter lang. Die Farbe der Drähte ist Ad_i_Israel. Schauen Sie sich das Angebot an:

roter (brauner) Draht (Vcc) mit einer Spannung von +5 bis +30 Volt.
schwarzer (weißer) Draht (OUT2)
grüner Draht (OUT1)
gelber Draht (GND)

Was hat verhindert, dass weiße / schwarze Erde entsteht? Übrigens sind auch beim Kranantrieb die logisch farbigen Drähte kein Ale. Der erste Sensor befindet sich in der Küche unter dem Waschbecken neben dem Geschirrspüler.



Der zweite im Badezimmer in einem speziellen Entwässerungsgraben. Als er den Estrich machte, brachte er ihn nicht an die Wand. Das Ergebnis war eine Art Sumpf zum Sammeln von Wasser aus Bad und Toilette.



Aus Betriebserfahrung - es gab bereits einen Fehlalarm des Sensors in der Spülmaschine. Gemessen am Protokoll für einen Abfragezyklus (500 ms) gab es eine Schaltung, die den Code modifizierte - die Zustandsänderung erfolgt nun bei 10 aufeinanderfolgenden identischen Werten vom Sensor.

Die Sensorkontakte sind vergoldet. Ein Freund hat seit mehreren Jahren ähnliche Sensoren, es wurde keine Oxidation festgestellt.

Drucksensoren


Praktisch - Showometer. Genauigkeit + - 0,5 atm passte mir vollkommen. Basierend auf den Sensoren wird ein Wasserabschaltalarm ausgegeben. Ali gekauft hier .

Temperatursensoren


Und warum nicht hinzufügen? Von nützlich - es wird einmal im Jahr in der Lage sein, über das Abschalten von heißem Wasser zu informieren. Gebraucht banal ds18b20.

Zähler


Das häufigste Itelma, einmal alle 10 Liter Kontakt aufnehmen. Auf der Controllerseite wird der Ausgang auf +3,3 V hochgezogen, das Messgerät zieht ihn auf den Boden.

Controller




Innen



Basierend auf dem Teilchenphoton, mehr Details hier . Sie haben eine Version mit einem 2G- oder 3G-Modul (Electron). Die erste Firmware war eine vollständige Schlacke, die mit OK-Dioden blinkte. Sobald Sie jedoch mit dem Kauen komplizierter Wurst beginnen, kann das Spielen mit i2c und Interrupts das WLAN verlieren. Jetzt kannst du leben. Im Prinzip können Sie Drucksensoren aus dem Stromkreis werfen und alles am ESP8266 aufrühren - los geht's. Erstens muss das Photon mit dem Partikelkonto verknüpft sein (über die App auf dem Handy oder über die Partikel-CLI-Konsole - ich verwende nur die zweite Methode) und ein WLAN-Netzwerk registrieren. Nach dem Binden werden hier im Geräteabschnitt der Controller und sein Status für die Verbindung zur Cloud angezeigt.



Ich habe alle Knoten nur zum Aktualisieren der Firmware mit der Cloud verbunden. Nicht, dass ich paranoid wäre - nur mit der Cloud zu arbeiten, kostet keine reichen Controller-Ressourcen. Die IDE unterstützt die Arbeit mit Bibliotheken, buchstäblich ein Dutzend werden vom Zähler selbst unterstützt, der Rest von der Community. Meiner Beobachtung nach wurde alles Gemeinsame schon lange portiert, und ein weiteres Merkmal ist, dass die IDE sofort weiß, wie viele Projekte die Bibliothek verwenden.

Firmware-Quellcode
// This #include statement was automatically added by the Particle IDE.
#include "Adafruit_SSD1306/Adafruit_SSD1306.h"

// This #include statement was automatically added by the Particle IDE.
#include "MQTT/MQTT.h"

// This #include statement was automatically added by the Particle IDE.
#include "OneWire/OneWire.h"

SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(MANUAL);
STARTUP(WiFi.selectAntenna(ANT_EXTERNAL));
STARTUP(System.enableFeature(FEATURE_RETAINED_MEMORY));

struct counter_struct {
  float value;
  byte state;
  int pin;
};
struct valve_struct {
  byte state;
  int pin;
};
struct sensor_struct {
  int timeout;
  byte state;
  int pin;
};

unsigned long currentMillis = 0;
unsigned long previous_conected = 100000; //  
unsigned long previous_wifi_uptime = 100000; //  
unsigned long previous_counter_read = 0; //  
unsigned long wifi_uptime;
unsigned long start_temp_timer = 0;
unsigned long read_temp_timer = 0;
byte display_timeout = 0;

//temp onewire 
OneWire ds0 = OneWire(D2);
OneWire ds1 = OneWire(D3);
byte addr0[8];
byte addr1[8];
bool presense0 = false;
bool presense1 = false;
byte data[12];

#define OLED_RESET A7
Adafruit_SSD1306 display(OLED_RESET);


//valve control
retained valve_struct valve[2] = { {0, D4}, {0, D5} };

//counter control
retained counter_struct counter[2] = { {0, 1, A0}, {0, 1, A1} };
volatile int pressure[2] = {A2, A3};
#define SENSOR_TIMEOUT 10
volatile sensor_struct sensor[2] = { {0, 1, D6}, {0, 1, D7} };

void callback(char* topic, byte* payload, unsigned int length);

byte server[] = { 192,168,2,101};
MQTT client(server, 1883, callback);

bool publish_message(const char* t, const char* p, bool retain) 
{
    return client.publish(t, (uint8_t*)p, sizeof(p), retain);
}

bool publish_message(const char* t, int p, bool retain) 
{   
    char buf_d[12];
    int n = sprintf(buf_d,"%d",p);
    return client.publish(t, (uint8_t*)buf_d, n, retain);
}

bool publish_message(const char* t, float p, bool retain) 
{   
    //char buf_f[18];
    String s(p, 4);
//    dtostrf(p, 9, 4, buf_f);
    //int n = sprintf(buf_f,"%f",p);
    return client.publish(t, (uint8_t*)s.c_str(), s.length(), retain);
}

// recieve message
void callback(char* topic, byte* payload, unsigned int length) {
    char p[length + 1];
    memcpy(p, payload, length);
    p[length] = NULL;
    String message(p);
    String t(topic);
    if (t.equals("home/water_count/spark/set"))
    {
        if (message.equalsIgnoreCase("1"))
        {
            Particle.connect();
            if (waitFor(Particle.connected, 10000)) 
                {publish_message("home/water_count/spark", 1, false);}
            else
                {Particle.disconnect(); publish_message("home/water_count/spark", 0, false);}
        }
        else
        {
            Particle.disconnect();
            publish_message("home/water_count/spark", 0, false);
        }
    }
    else if (t.startsWith("home/water_count/valve/"))
    {
        int m = message.toInt();
        int x = t.substring(23,24).toInt();
        if (m > -1 && m < 2 && x > -1 && x <2) 
        {
            set_valve(x, m);
        }
        else
        {
            publish_message("home/water_count/valve/" + t.substring(23,24),  valve[x].state , true);
        }
    }
    else if (t.startsWith("home/water_count/counter/"))
    {
        float m = message.toFloat();
        int x = t.substring(25,26).toInt();
        if (m > -1 && m <= 999999 && x > -1 && x <2) 
        {
            counter[x].value = m;
        }
        publish_message("home/water_count/counter/" + t.substring(25,26),  counter[x].value , true);
    }
}

void setup() {
//Serial.begin(9600);
    WiFi.on();
    WiFi.connect();
    if (waitFor(WiFi.ready, 5000)) {mqtt_connect();}
    for (int i=0; i < 2; i++) 
    {
        pinMode(valve[i].pin, OUTPUT);
        digitalWrite(valve[i].pin, valve[i].state);
        pinMode(counter[i].pin, INPUT);
        pinMode(sensor[i].pin, INPUT);
        counter[i].state = digitalRead(counter[i].pin);
        pinMode(pressure[i], AN_INPUT);
    }
    pinMode(A4, INPUT_PULLUP);

    display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C (for the 128x64)
    display.clearDisplay();   // clears the screen and buffer

    //Particle.connect();
}

void loop() 
{
    currentMillis = millis();
    //       MQTT 
    if (currentMillis - previous_conected >= 30000 || previous_conected > currentMillis)
    {
        previous_conected = currentMillis;
        if (!client.isConnected() & wifi_uptime > 60)
        {
            mqtt_connect();
        }
        publish_message("home/water_count/rssi", WiFi.RSSI(), true);
    }
    if (currentMillis - previous_wifi_uptime >= 1000 || previous_wifi_uptime > currentMillis)
    {
        previous_wifi_uptime = currentMillis;
        WiFi.ready() ? wifi_uptime++ : wifi_uptime = 0;
        //work with button and display
        int fg = digitalRead(A4);
        if (display_timeout > 0)
        {
            display_timeout -= 1;
            if (display_timeout == 0) 
            { 
                display.clearDisplay();
                display.display();
            } 
        }
        if (fg == 0)
        {
            if (display_timeout == 0)
            {
                display.clearDisplay();   // clears the screen and buffer
                display.setTextSize(2);
                display.setTextColor(WHITE);
                display.setCursor(0,0);
                display.print("C=");
                display.println(counter[0].value, 4);
                display.setCursor(0,16);
                display.print("H=");
                display.println(counter[1].value, 4);
                display.setCursor(0,32);
                display.print("Valve=");
                display.print(valve[0].state);
                display.print("|");
                display.println(valve[1].state);
                display.setCursor(0,48);
                display.print("Sensor=");
                display.print(sensor[0].state);
                display.print("|");
                display.println(sensor[1].state);
                display.display();
            }
            display_timeout = 10;
        }
    }
    //counter check
    if (currentMillis - previous_counter_read >= 500 || previous_counter_read > currentMillis)
    {
        previous_counter_read = currentMillis;
        for (int i=0; i < 2; i++) 
        {
            byte count_state = digitalRead(counter[i].pin);
            if (count_state != counter[i].state)
            {
                counter[i].state = count_state;
                if (count_state == 0)
                {
                    counter[i].value += 0.01;
                    char buf18[30];
                    sprintf(buf18,"home/water_count/counter/%d", i);
                    publish_message(buf18 , counter[i].value, true);
                }
            }
            //    
            byte sensor_state = digitalRead(sensor[i].pin);
            if (sensor_state != sensor[i].state) //
            {
                sensor[i].state = sensor_state;
                sensor[i].timeout = SENSOR_TIMEOUT; 
            }
            if (sensor[i].timeout > 0) 
            {
                sensor[i].timeout -= 1;
                if (sensor[i].timeout == 0)
                {
                    char buf18[30];
                    sprintf(buf18,"home/water_count/sensor/%d", i);
                    publish_message(buf18 , sensor[i].state, true);
                    if (sensor[i].state  == 0)
                    {
                        set_valve(0, 1); //close both valve
                        set_valve(1, 1); //close both valve
                    }
                }
            }
        }
    }

    // temp onewire
    if (currentMillis - start_temp_timer >= 299000 || start_temp_timer > currentMillis)
    { // 
        start_temp_timer = currentMillis;
        presense0 = start_temp0();
        presense1 = start_temp1();
    }
    if (currentMillis - read_temp_timer >= 300000 || read_temp_timer > currentMillis)
    {// 
        read_temp_timer = currentMillis;
        start_temp_timer = currentMillis;
        if (presense0) read_temp0();
        if (presense1) read_temp1();
        //preasure calc and send
        char buf18[30]; 
        for (int i=0; i < 2; i++)
        {
            sprintf(buf18,"home/water_count/pressure/%d", i);
            float read_val = analogRead(pressure[i]);
            float value = (read_val - 600.0) / 300.0 ;
            publish_message(buf18 , value, false);
        }
    }
    //Particle.process();
    client.loop();
}

void mqtt_connect()
{
    if (client.connect("water_count"))
    { //  spark    
        client.subscribe("home/water_count/spark/set");
        publish_message("home/water_count/spark", Particle.connected() ? 1 : 0, true);
        client.subscribe("home/water_count/valve/+/set");
        client.subscribe("home/water_count/counter/+/set");
        
    }
}

bool start_temp0()
{
    
    if ( !ds0.search(addr0)) { ds0.reset_search(); return false;}
    ds0.reset_search();
    if (OneWire::crc8(addr0, 7) != addr0[7]) { return false;}
    
    ds0.reset();
    ds0.select(addr0);
    ds0.write(0x44, 0);
    return true; 
}
bool start_temp1()
{
    
    if ( !ds1.search(addr1)) { ds1.reset_search(); return false;}
    ds1.reset_search();
    if (OneWire::crc8(addr1, 7) != addr1[7]) { return false;}
    
    ds1.reset();
    ds1.select(addr1);
    ds1.write(0x44, 0);
    return true; 
}

bool read_temp0()
{
    //delay(1000);
    ds0.reset();
    ds0.select(addr0);
    ds0.write(0xBE, 0);

    for (int i = 0; i < 9; i++) 
    {
        data[i] = ds0.read();
    }
    int16_t raw = (data[1] << 8) | data[0];
    float celsius = (float)raw * 0.0625;
    if (celsius < 0 || celsius > 100) return false;
    publish_message("home/water_count/temp/0", celsius, false);
    //Serial.println(celsius);
    ds0.reset_search();
    return true;
}
bool read_temp1()
{
    //delay(1000);
    ds1.reset();
    ds1.select(addr1);
    ds1.write(0xBE, 0);

    for (int i = 0; i < 9; i++) 
    {
        data[i] = ds1.read();
    }
    int16_t raw = (data[1] << 8) | data[0];
    float celsius = (float)raw * 0.0625;
    if (celsius < 0 || celsius > 100) return false;
    publish_message("home/water_count/temp/1", celsius, false);
    //Serial.println(celsius);
    ds1.reset_search();
    return true;
}

void set_valve(int vlv, byte state)
{
    valve[vlv].state = state;
    digitalWrite(valve[vlv].pin, state);
    char buf26[26];
    sprintf(buf26,"home/water_count/valve/%d", vlv);
    publish_message(buf26 , state , true);
}


Über MQTT verbinden wir uns mit dem Broker. Überwachen Sie die Sensoren und den Helm in den entsprechenden Zweigen der mqtt-Ereignisse und -Werte. Zum Beispiel home / water_count / ventil / 0 - ein Wasserantrieb. home / water_count / counter / 0 - Messwerte des Zählers eines kalten Wassers.

Wir abonnieren die Befehle zum Ändern des Laufwerkszustands und zum Einstellen des aktuellen Werts des Zählers (kaltes und heißes Wasser):

client.subscribe("home/water_count/valve/+/set");
client.subscribe("home/water_count/counter/+/set");

Es gibt eine Taste am Gerät - durch Drücken schalten wir den Bildschirm ein und zeichnen die aktuellen Messwerte von Zählern, Sensoren und Abgriffen. OLED-Bildschirm, verblasst schnell, wenn er ständig eingeschaltet ist.

STARTUP(System.enableFeature(FEATURE_RETAINED_MEMORY));

Dies ist eine interessante Hardware- und Softwarefunktion des stm-Controllers, die im Referenzteilchen als BackupSRAM bezeichnet wird. Photon hat einen VBAT-Ausgang - dies ist keine Batterieleistung oder Aufladung. Solange an diesem Zweig Spannung anliegt, bleibt der Inhalt von 4 KByte SRAM erhalten, wobei die Steuerung vollständig stromlos ist. Dies beseitigt das Problem des Verschleißes des EEPROM.

Im Code werden die Variablen, die in diesen Speicher gefahren werden müssen, mit dem Hinweis deklariert: beibehalten. Ich habe Hardware vom Superkondensator bei 1,5F implementiert. Laut Datenblatt wird der Speicher bei 1,6 V sterben, nach meinen Bench-Experimenten auf dem Protoboard wird es in 2 Wochen mit ungefähr meinem Kondensator kommen. Die Logik des Schließens der Krane beim Auslösen der Sensoren ist "autonom" und hängt nicht von der Verbindung zu openhab ab. Es gibt einen 3-Wege-Schalter für die Direktantriebssteuerung - automatisch, AUS (offene Hähne), Schließen (schließen).

Der folgende Schaltplan:



Das Eagle-Projekt kann zusammen mit benutzerdefinierten Bibliotheken hier heruntergeladen werden .

Die Gebühr wurde LUT gemacht, in den Tracks schrumpfte nicht.

Wasserbad LUTs bester Freund


Netzteil. Wir brauchen 12 und 5 Volt. Der Spender wird bei ebay nach der Zeile "Festplatten-Netzteil 5V 12V" wie dieser durchsucht .

Gehäuse


Es wurde mit PLA-Kunststoff auf einem 3D-Drucker (Tarantula Tevo) gedruckt. Düse 0,4 mm, Schicht 0,25 mm. Die Abdeckung ist gleichzeitig und die Basis für die Montage der Controller-Karte. Die Basis mit dem Netzteil ist an der Wand befestigt. Die Basis mit dem Deckel ist nicht mit Schrauben befestigt, es gibt genügend Deckelspannung (wie der Deckel der Großmutter auf Marmeladengläsern) und die Schichtstruktur der Wände funktioniert.

3D-Modell im Archiv .





So sieht alles auf einer Wasserleitung montiert aus.



Openhab


Bereitgestellt auf Orange Pi One unter Armbian.

Item Config
  -    ,  .
Number	watercount_temp1	"T cool [%.1f °C]"			(gWaterCount)		{ mqtt="<[mqtt_bro:home/water_count/temp1:state:default]" }
Number	watercount_temp2	"T hot [%.1f °C]"			(gWaterCount)		{ mqtt="<[mqtt_bro:home/water_count/temp2:state:default]" }
Number	watercount_count0	"Count cool [%.2f ³]"					(gWaterCount)		{ mqtt="<[mqtt_bro:home/water_count/counter/0:state:default]" }
Number	watercount_count1	"Count hot [%.2f ³]"				(gWaterCount)		{ mqtt="<[mqtt_bro:home/water_count/counter/1:state:default]" }
Number	watercount_pressure0	"P cool [%.2f .]"			(gWaterCount)		{ mqtt="<[mqtt_bro:home/water_count/pressure/0:state:default]" }
Number	watercount_pressure1	"P hot [%.2f .]"				(gWaterCount)		{ mqtt="<[mqtt_bro:home/water_count/pressure/1:state:default]" }
Number	watercount_sensor0	"Sensor0 is [MAP(water_sensor.map):%s]"		(gWaterCount)		{ mqtt="<[mqtt_bro:home/water_count/sensor/0:state:default]" }
Number	watercount_sensor1	"Sensor1 is [MAP(water_sensor.map):%s]"		(gWaterCount)		{ mqtt="<[mqtt_bro:home/water_count/sensor/1:state:default]" }
Number	watercount_valve0	"Valve cool"		(gWaterCount)		{ mqtt="<[mqtt_bro:home/water_count/valve/0:state:default], >[mqtt_bro:home/water_count/valve/0/set:command:*:default]" }
Number	watercount_valve1	"Valve hot"				(gWaterCount)		{ mqtt="<[mqtt_bro:home/water_count/valve/1:state:default], >[mqtt_bro:home/water_count/valve/1/set:command:*:default]" }
String	watercount_sendStr "LastVol:[%s]"						(gWaterCount)
Number	watercount_sendCool "Send cool [%.2f ³]"		(gWaterCount)
Number	watercount_sendHot "Send hot [%.2f ³]"			(gWaterCount)
Number	watercount_sendSwitch "Autosend" 	(gWaterCount)
Number	watercount_rssi	"WaterCount [%d dB]"	(gSpark_RSSI)		{ mqtt="<[mqtt_bro:home/water_count/rssi:state:default]" }
Number	watercount_spark_state	"WaterCount Spark"		(gSpark)		{ mqtt="<[mqtt_bro:home/water_count/spark:state:default], >[mqtt_bro:home/water_count/spark/set:command:*:default]" }


Für den Lecksensor wird eine kleine Transformationsregel benötigt.

Konfigurationen transformieren
transform\water_sensor.map
1=dry
0=wet
undefined=undefined

Wir bilden die Seite für das Management:

Konfiguriert Sitemap
Sitemap
Text label=«» icon=«water»
{
Frame
{
Text item=watercount_temp1
Text item=watercount_count0
Text item=watercount_pressure0
Switch item=watercount_valve0 mappings=[1=«Close», 0=«Open»]
}
Frame
{
Text item=watercount_temp2
Text item=watercount_count1
Text item=watercount_pressure1
Switch item=watercount_valve1 mappings=[1=«Close», 0=«Open»]
}
Frame
{
Text item=watercount_sensor0
Text item=watercount_sensor1
}
Frame
{
Switch item=watercount_sendSwitch mappings=[0=«OFF», 1=«ON»]
Text item=watercount_sendStr
Text item=watercount_sendCool
Text item=watercount_sendHot
}
}

Und Verarbeitungsregeln:

Konfigurationsregeln
rule "Check watercount_sensor0"
	when
		Item watercount_sensor0 received update
	then
		if ((watercount_sensor0.state as DecimalType) == 1)
		{
			if ((watercount_sensor0.historicState(now.minusSeconds(3)).state as DecimalType) == 1)
			{
				sendTelegram("****_bot", "Sensor0 was wet less than 5 seconds")
			}
			else
			{
				sendTelegram("****_bot", "Sensor0 become dry")
			}
		}
		else
		{
			if ((watercount_sensor0.historicState(now.minusSeconds(3)).state as DecimalType) == 0)
			{
				sendTelegram("****_bot", "Sensor0 was dry less than 5 seconds");			
			}
			else
			{
				sendTelegram("****_bot", "Sensor0 become wet! Valves will be closed!")
			}
		}
	end
rule "Check watercount_sensor1"
	when
		Item watercount_sensor1 received update
	then
		if ((watercount_sensor1.state as DecimalType) == 1)
		{
			if ((watercount_sensor1.historicState(now.minusSeconds(3)).state as DecimalType) == 1)
			{
				sendTelegram("****_bot", "Sensor1 was wet less than 5 seconds")
			}
			else
			{
				sendTelegram("****_bot", "Sensor1 become dry")
			}
		}
		else
		{
			if ((watercount_sensor1.historicState(now.minusSeconds(3)).state as DecimalType) == 0)
			{
				sendTelegram("****_bot", "Sensor1 was dry less than 5 seconds");			
			}
			else
			{
				sendTelegram("****_bot", "Sensor1 become wet! Valves will be closed!")
			}
		}
	end
	
rule "Check watercount_temp2"
	when
		Item watercount_temp2 received update
	then
		if ((watercount_temp2.state as DecimalType) < 37 )
		{
			sendTelegram("****_bot", String::format("Hot water temp drop to %s", watercount_temp2.state.toString));
		}
	end

rule "Check watercount_pressure0"
	when
		Item watercount_pressure0 received update
	then
		if ((watercount_pressure0.state as DecimalType) < 1 && (watercount_pressure0.historicState(now.minusSeconds(3)).state as DecimalType) >= 1)
		{
			sendTelegram("****_bot", String::format("Cool pressure drop to %s", watercount_pressure0.state.toString));
		}
		if ((watercount_pressure0.state as DecimalType) > 1 && (watercount_pressure0.historicState(now.minusSeconds(3)).state as DecimalType) <= 1)
		{
			sendTelegram("****_bot", String::format("Cool pressure rise to %s", watercount_pressure0.state.toString));
		}
	end
rule "Check watercount_pressure1"
	when
		Item watercount_pressure1 received update
	then
		if ((watercount_pressure1.state as DecimalType) < 1 && (watercount_pressure1.historicState(now.minusSeconds(3)).state as DecimalType) >= 1)
		{
			sendTelegram("****_bot", String::format("Hot pressure drop to %s", watercount_pressure1.state.toString));
		}
		if ((watercount_pressure1.state as DecimalType) > 1 && (watercount_pressure1.historicState(now.minusSeconds(3)).state as DecimalType) <= 1)
		{
			sendTelegram("****_bot", String::format("Hot pressure rise to %s", watercount_pressure1.state.toString));
		}
	end

rule "Generate send string counters" //every 24 day of mounth  in 00.01 minutes
	when
		Time cron "0 0 1 24 1/1 ?" 
	then
		
		var float deltaCool = (watercount_count0.state as DecimalType).floatValue() - (watercount_sendCool.state as DecimalType).floatValue()
		var float deltaHot = (watercount_count1.state as DecimalType).floatValue() - (watercount_sendHot.state as DecimalType).floatValue()
		
		if (deltaCool >= 0 && deltaHot >= 0)
		{
			watercount_sendStr.postUpdate(String::format(" %.2f / %.2f 3", deltaCool, deltaHot))
			watercount_sendCool.state = watercount_count0.state
			watercount_sendHot.state = watercount_count1.state
			sendTelegram("****_bot", String::format(" 23,  5, . 23.  №2560097 (.) = %.2f 3. C №2538996 (.) = %.2f 3. %s", (watercount_sendCool.state as DecimalType).floatValue(), (watercount_sendHot.state as DecimalType).floatValue(), watercount_sendStr.state.toString()))
		}
		else
		{
			watercount_sendSwitch.postUpdate(0)
			sendTelegram("****_bot", "Current counters value less than sended last time. Turn off autosend.")
		}
end
rule "Send string counters" 
	when
		Time cron "0 0 23 24 1/1 ?"
	then
		if (watercount_sendSwitch.state == 1)
		{
			sendMail("uk@uk.ru", " 23,  5, . 23", String::format(" 23,  5, . 23.  №2560097 (.) = %.2f 3. C №2538996 (.) = %.2f 3", (watercount_sendCool.state as DecimalType).floatValue(), (watercount_sendHot.state as DecimalType).floatValue()));
			sendTelegram("****_bot", "Send email with watercount values");
		}
		else
		{
			sendTelegram("****_bot", "Can't send email with watercount values - autosend is OFF.");
		}
end
rule "Rotate valves" 
	when
		Time cron "0 0 05 25 1/1 ?"
	then
		if (watercount_valve0.state == 0 && watercount_valve1.state == 0)
		{	
			watercount_valve0.postUpdate(1)
			Thread::sleep(1000)
			watercount_valve1.postUpdate(1)
			Thread::sleep(1000)
			watercount_valve0.postUpdate(0)
			Thread::sleep(1000)
			watercount_valve1.postUpdate(0)
			sendTelegram("****_bot", "Valves was rotated.");
		}
		else
		{
			sendTelegram("****_bot", "Can't rotate valves, it's closed.");
		}
end


Zum Senden von Nachrichten verwende ich weder die integrierte Funktionalität der Openhab-Android-Anwendung noch integriere ich sie in deren Cloud. Ich mag den Telegramm-Bot. Wie Sie den Bot konfigurieren und verbinden, erfahren Sie im Wiki . Um Briefe aus dem Google Mail-Postfach zu senden, müssen Sie bei einer Zwei-Faktor-Authentifizierung ein Einmalkennwort für die E-Mail-Anwendung aktivieren und dieses Kennwort in der Openhab-Konfiguration festlegen.

Befolgen Sie die Regeln.

Überprüfen Sie watercount_sensor- Die Steuerung sendet nur dann neue Lecksensorwerte, wenn der Wert geändert wird oder wenn ein Fehlalarm aufgetreten ist (weniger als 10 Zyklen). Wir analysieren die kam und historische Bedeutung, wir bilden Informationsbotschaften. Es gibt eine Nuance - ein Versuch, prevoiusItem zu erhalten, gibt ständig den aktuellen Wert an, ich habe keine Lösung gefunden - ich nehme den Wert "-3 Sek.", Wenn jemand ihn überwunden hat, schreibe ihn in Kommentaren oder in PM auf.

Überprüfen Sie watercount_temp2 - prüfen Sie, ob weniger als 37, was bedeutet, dass heißes Wasser kalt geworden ist, die Durchflussheizung bei der Ankunft einschalten müssen.

Überprüfen Sie watercount_pressure - wir analysieren den aktuellen und vorherigen Wert und antworten mit einer Meldung auf einen Abfall unter 1 atm und ein Wachstum darüber.

Generieren Sie Sendezeichenfolgenzähler- beginnt am 24. eines jeden Monats um 1 Uhr morgens mit cron. Wir überprüfen, ob die Werte jetzt größer sind als die zuletzt gesendeten. Wenn weniger, deaktivieren Sie das automatische Senden und generieren Sie eine Warnung. Wenn OK - wir erinnern uns an die Werte der Zähler für das Senden an das Strafgesetzbuch, senden wir den zukünftigen Nachrichtentext an das Telegramm. Gleichzeitig sparen wir in watercount_sendStr, wie viel wir im letzten Monat verbraucht haben.

Sende-String-Zähler generieren - startet am 24. Tag um 23.00 Uhr auf cron. Überprüft, ob das automatische Senden aktiviert ist, wenn es aktiviert ist. Der Helm sendet Zähler an die Post der Reederei. Es stellt sich heraus, dass ich den 24. Tag den ganzen Tag Zeit habe, um das automatische Senden zu beheben oder einfach zu reduzieren, wenn in den Telegrammen ein Fehler aufgetreten ist.

Update durch Kommentar . Ventile drehen- Die Regel zum einmal monatlichen Schließen / Öffnen des Wasserhahns gegen Kochen. Der 25. um 5 Uhr morgens - um nicht in die Arbeit des Geschirrspülers oder der Waschmaschine zu gelangen, aber selbst wenn er dort ankommt - ist es nicht kritisch, dass die Überlappung des Wassers etwa 3-4 Sekunden beträgt.

Und erst hier beginnt das Smart Home ...
Durch die Kombination von Systemen in einem einzigen Punkt (Openhab) können Sie Logik erstellen, die für eine Reihe autonomer Systeme nicht verfügbar ist. Zum Beispiel: Ein Ereignis mit einer Erhöhung des Wasserzählers ist eingetroffen - das Sicherheitssystem ist aktiv, die Schlösser der Vordertür sind geschlossen, der Energieverbrauch des Geschirrspülers und der Waschmaschine beträgt weniger als 5 Watt - was bedeutet, dass ein Leck durch die Sensoren erkannt wird. Wir bilden einen Befehl zum Schließen der Kräne und senden eine Nachricht an den Bot im Telegramm. Aber das ist später wie ein Thread.

Source: https://habr.com/ru/post/de399459/


All Articles