Blackjack dan perlindungan kebocoran balik

Salam Ada hal seperti itu - hydrolock \ neptune \ avkvastorozh - sistem pematian air jika terjadi kebocoran yang tidak terkendali. Prinsipnya sederhana - sensor air + otomatisasi + sepasang keran listrik. Tetapi iblis, seperti biasa, ada dalam rincian: bagaimana keran diatur, bagaimana sensor kebocoran diatur, dan mengapa satu biaya 50 rubel dan yang lain biaya 500 rubel. Satu kilogram buletin tata letak akan melilit semua ini, kemasan akan mengeluarkan mata Anda, dll.

Dalam cerita saya akan berjalan melalui batu bata sistem, yang membimbing saya dalam pilihan. Seluruh sistem dibangun di atas sensor pabrik dan pengontrol buatan sendiri berdasarkan Partikel (ex.Spark) Photon (seperti esp8266 yang memiliki IDE cloud pada pengkabelan di luar kotak), basis perangkat adalah pengontrol stm + modul wifi dari Broadcom. Semua ini terkait dengan server openhab di Orange Pi One.



Mengapa bukan sistem yang sudah selesai?

- Karena saya bisa melakukannya sendiri dan ini tinggi
- Integrasi dengan sistem eksternal lemah dalam sistem yang sudah jadi.
- Sistem siap pakai tidak memiliki fungsi tambahan - memperhitungkan pembacaan meter, sensor suhu air, pemberitahuan pemadaman air dan fantasi erotis berjalan lainnya.

Mari kita mulai dengan crane


Memilih bodoh di dahi dalam hal torsi. Untuk beberapa waktu ia tinggal di pinggiran kota, di mana kualitas air (mungkin di mana-mana di Zamkadye) menyisakan banyak yang diinginkan. Jadi bola valves 1/2 inci jika Anda tidak menyentuh tahun - sangat sulit untuk berputar. Dan pada gantungan handuk 1 inci yang dipanaskan, saya bahkan tidak mencoba untuk memindahkannya - hanya jika saya memperkuat bahu dengan kunci inggris, tetapi di sini Anda dapat merobek sesuatu. Masalahnya ada pada endapan kalsium-kayu, "ditumbuhi" dengan satu kata.

Dengan demikian, pilihan jatuh pada seri profesional dari hydrolock - 21N * m torsi tidak terasa seperti obrolan iklan, crane sangat besar - mengevaluasi tempat pemasangannya sebelum membeli.



Keran disegel, segel karet di sekeliling, pintu masuk di bawah kelenjar sekrup.
Lepaskan penutup.



Di depan kita ada papan atas dan motor stepper. Semua ini didukung oleh 12 volt. Shorting kabel kontrol ke tanah menempatkan katup dalam posisi tertutup. Di papan tulis kita melihat pengontrol PIC 12f629 sederhana. Tinggal, controller di drive derek.

Bagian belakang papan adalah yang paling menarik.



L293 driver shagovik dan photocoupler (emitor + photodetector). Dia melihat gigi utama drive, yang dicat bagian - putih dan hitam, tertutup / terbuka.



Derek berputar sepanjang waktu dalam satu arah, logika pengontrolnya sederhana - kita memutar poros sampai kita beralih ke warna yang diinginkan. Rotasi crane dalam satu arah adalah keausan yang lebih sedikit, dan cara non-kontak untuk menentukan posisi lebih kecil kemungkinannya untuk memburuk / tidak berfungsinya resistor variabel atau sakelar batas.

Untuk pemasangan, Anda dapat melepaskan crane dari drive - dipegang dengan 2 mur. Ada gasket isolasi panas antara drive dan derek.



Saya memiliki perbaikan satu setengah tahun yang lalu. Derek itu dibeli tiga tahun lalu - untuk membongkar, melihat ke dalam, membeli lebih banyak dan memutarnya selama perbaikan. Ya, sekarang ... maksimum yang saya kelola di sirkus neraka ini adalah meletakkan pengumpul debu di dalam rakitan pasokan air dengan prospek untuk menggantinya dengan crane.
Dan hanya setelah satu setengah tahun - saya membeli crane kedua dan mengacaukannya.

Akibatnya, kami mengamati fenomena aneh dan langka (baca di suara Drozdov) - semua informasi dari situs web produsen dikonfirmasi. Selain itu, uraiannya aneh, seolah-olah para teknisi menulis, dan kemudian pemasaran disiram untuk orang-orang, tetapi masih sedikit orang yang mengerti semua chip. Tidak ada bagian yang cukup di situs - untuk integrator dengan detail teknis di dalamnya. Bahkan dengan mengorbankan peningkatan torsi, mereka tidak berbohong di awal - derek di poni awal dengan mesin 1,5A dan setelah 2-3 detik mulai naik dalam mode normal (0,7 A) saat ini. Dibutuhkan sekitar 25-30 detik untuk menutup.

Pengalaman lain: dengan mengorbankan torsi - ini berlebihan untuk waktu Moskow, di sini airnya cukup oke, selama satu setengah tahun dalam filter 100 μm ada sepasang sampah dan tidak ada pertumbuhan berlebihan. Anda harus membayar untuk torsi besar dengan harga, waktu pembukaan, dan tempat di lemari. Saya pikir akan ada cukup drive konvensional dari Hydrolock Ultimate, Neptune atau Aquastorozh. Saya tidak bisa menjamin untuk dua terakhir - saya tidak bisa keluar, sekitar 5 tahun yang lalu mereka memiliki sebagian roda gigi plastik, sekarang mereka tampaknya telah memperbaikinya.

Ada juga hydrolock Pemenang dengan koneksi sensor langsung ke drive - ini adalah jika Anda tidak membutuhkan semua yang telah saya lakukan. Di sana, daya otonom dari 4 baterai, dan pangkalan mirip dengan drive utama. Secara umum, ini juga berpotensi menarik untuk pengontrol buatan sendiri - 5 volt, Anda tidak perlu menempatkan dua bus pada volt 5 dan 12 dan Anda dapat membuang isolasi optik.

Sensor kebocoran


Saya membeli sensor konter WSU yang sama - universal. Mereka memiliki dua output "kolektor terbuka", satu menarik ke tanah hanya jika ada air, yang kedua - jika air masuk, itu menarik ke tanah sepanjang waktu sampai listrik terputus. Saya hanya menggunakan output pertama, sisa logika ada di controller, tetapi sepertinya output ini dapat berguna untuk beberapa sistem pengiriman kondominium.

Kabel dalam kit berada tiga meter di suatu tempat. Warna kabelnya adalah Ad_i_Israel. Lihatlah kutipannya:

kabel merah (coklat) (Vcc) diaktifkan dari +5 hingga +30 volt.
kawat hitam (putih) (OUT2)
kawat hijau (OUT1)
kawat kuning (GND)

Inilah yang dicegah membuat bumi putih / hitam? Pada drive crane, omong-omong, kabel berwarna dengan logika bukan bir. Sensor pertama ada di dapur, di bawah wastafel di sebelah mesin cuci piring.



Yang kedua di kamar mandi di selokan drainase khusus. Ketika dia melakukan screed, dia tidak membawanya ke dinding. Hasilnya adalah semacam bah untuk menampung air dari kamar mandi dan toilet.



Dari pengalaman operasi - sudah ada satu alarm palsu dari sensor di mesin pencuci piring. Dilihat oleh log untuk satu siklus pemungutan suara (500 ms) ada sirkuit, dimodifikasi kode - perubahan negara sekarang terjadi pada 10 nilai identik berturut-turut dari sensor

Kontak sensor berlapis emas. Seorang teman memiliki sensor serupa selama beberapa tahun, tidak ada oksidasi yang terlihat.

Sensor tekanan


Praktis - showometer. Akurasi + - 0,5 atm sangat cocok untuk saya. Berdasarkan sensor, peringatan shutdown air datang. Saya membeli Ali di sini .

Sensor suhu


Dan mengapa tidak menambahkan? Dari berguna - itu akan dapat menginformasikan setiap tahun tentang penutupan air panas. Ds18b20 dangkal bekas.

Penghitung


Itelma yang paling umum, setiap 10 liter melakukan kontak. Di sisi pengontrol, output ditarik ke + 3.3V, meteran menariknya ke tanah.

Pengendali




Di dalam



Berdasarkan Partikel Foton, lebih detail di sini . Mereka memiliki versi dengan modul 2G atau 3G (Electron). Firmware pertama adalah slag lengkap, berkedip dengan dioda OK, tetapi segera setelah Anda mulai sosis yang kenyal, bermain dengan i2c dan interupsi dapat kehilangan wifi. Sekarang kamu bisa hidup. Pada prinsipnya, Anda dapat membuang sensor tekanan dari sirkuit dan menggerakkan segala sesuatu pada ESP8266 - lakukan saja. Pertama, foton harus ditautkan ke akun partikel (dilakukan melalui Aplikasi di ponsel atau melalui konsol Partikel CLI - Saya hanya menggunakan metode kedua) dan mendaftarkan jaringan wifi. Setelah mengikat, di sini di bagian perangkat muncul controller dan statusnya terhubung ke cloud.



Saya memiliki semua node yang terhubung ke cloud hanya untuk memperbarui firmware. Bukan berarti saya akan menjadi paranoid - hanya bekerja dengan cloud makan bukan sumber daya controller kaya. IDE mendukung bekerja dengan perpustakaan, secara harfiah selusin didukung oleh penghitung itu sendiri, sisanya oleh komunitas. Dalam pengamatan saya, semua yang umum telah diangkut sejak lama, dan fitur lainnya adalah bahwa IDE segera tahu berapa banyak proyek yang menggunakan pustaka.

Kode sumber firmware
// 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);
}


Melalui MQTT kami terhubung ke broker. Monitor sensor dan helm di cabang yang sesuai dari acara dan nilai mqtt. Misalnya rumah / water_count / katup / 0 - drive air. home / water_count / counter / 0 - pembacaan counter air dingin.

Kami berlangganan perintah untuk mengubah keadaan drive dan menetapkan nilai saat ini dari penghitung (air dingin dan panas):

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

Ada satu tombol pada perangkat - dengan menekan kita menghidupkan layar, menggambar bacaan counter saat ini, sensor dan ketukan. Layar OLED, cepat memudar jika dihidupkan sepanjang waktu.

STARTUP(System.enableFeature(FEATURE_RETAINED_MEMORY));

Ini adalah fitur perangkat keras dan perangkat lunak yang menarik dari pengontrol stm, dalam Partikel referensi mereka menyebutnya BackupSRAM. Foton memiliki output vbat - ini bukan daya baterai atau pengisian daya. Selama ada tegangan pada kaki ini, isi SRAM 4k byte dipertahankan dengan pengontrol yang sepenuhnya tidak berenergi. Ini menghilangkan masalah keausan pada EEPROM.

Dalam kode, variabel yang harus didorong ke dalam memori ini dinyatakan dengan indikasi: dipertahankan. Saya menerapkan perangkat keras dari supercapacitor di 1.5F. Menurut datasheet, memori akan mati di 1.6v, menurut percobaan bangku saya di proto-board itu akan datang dalam 2 minggu dengan tentang kapasitor saya. Logika menutup crane ketika sensor dipicu adalah "otonom" dan tidak tergantung pada koneksi ke openhab. Ada saklar 3 arah untuk kontrol drive langsung - otomatis, OFF (keran terbuka), Tutup (tutup).

Diagram sirkuit di bawah ini:



Proyek Elang, bersama dengan lib kustom, dapat diunduh di sini .

Biaya dibuat LUT, di trek tidak menyusut.

Pemandian air, sahabat terbaik LUT


Unit catu daya. Kami membutuhkan 12 dan 5 volt. Donatur dicari di ebay untuk saluran: "adaptor daya hard drive 5v 12v", seperti ini .

Perumahan


Itu dicetak dengan plastik PLA pada printer 3d (Tarantula Tevo). Nozzle 0.4mm, lapisan 0.25mm. Penutup pada saat yang sama dan alas untuk memasang papan pengontrol. Basis dengan catu daya terpasang ke dinding. Basis dengan tutupnya tidak diikat dengan sekrup, ada ketegangan tutup yang cukup (seperti tutup nenek di stoples selai) dan struktur dinding yang berlapis berfungsi.

Model 3D dalam arsip .





Beginilah tampilannya terpasang di pipa air.



Openhab


Dikerjakan di Orange Pi One di bawah Armbian.

Konfigurasi Barang
  -    ,  .
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]" }


Diperlukan aturan transformasi kecil untuk sensor kebocoran.

Konfigurasi berubah
transform\water_sensor.map
1=dry
0=wet
undefined=undefined

Kami membentuk halaman untuk manajemen:

Konfigurasikan Peta Situs
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
}
}

Dan aturan pemrosesan:

Aturan Konfigurasi
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


Untuk mengirim pesan, saya tidak menggunakan fungsionalitas built-in dari aplikasi android openhab, juga tidak saya integrasikan dengan cloud mereka. Saya suka bot Telegram. Cara mengkonfigurasi dan menghubungkan bot dapat dilihat di wiki . Untuk mengirim surat dari kotak surat gmail, jika Anda memiliki otentikasi dua faktor, Anda perlu mengaktifkan kata sandi satu kali untuk aplikasi surat dan mengatur kata sandi ini di konfigurasi openhab.

Berjalan sesuai aturan.

Periksa watercount_sensor- pengontrol mengirimkan nilai sensor kebocoran baru hanya ketika nilainya diubah atau jika ada alarm palsu (kurang dari 10 siklus). Kami menganalisis makna datang dan historis, kami membentuk pesan informasi. Ada nuansa - upaya untuk mendapatkan prevoiusItem terus-menerus memberikan nilai saat ini, saya belum menemukan solusi - Saya mengambil nilai "-3 detik", jika seseorang mengatasinya, tuliskan dalam komentar atau di PM.

Periksa watercount_temp2 - periksa apakah kurang dari 37, artinya air panas telah menjadi dingin, Anda harus menghidupkan pemanas pada saat kedatangan.

Periksa watercount_pressure - kami menganalisis nilai saat ini dan sebelumnya, kami merespons dengan pesan hingga turun di bawah 1 atm dan pertumbuhan di atasnya.

Hasilkan penghitung string pengirim- Dimulai dengan cron pada tanggal 24 setiap bulan pada pukul 1 pagi. Kami memeriksa bahwa nilainya sekarang lebih besar daripada yang dikirim terakhir kali. Jika kurang, matikan pengiriman otomatis dan buat lansiran. Jika OK - kami mengingat nilai-nilai penghitung untuk dikirim ke KUHP, kami mengirim badan pesan di masa depan ke telegram. Pada saat yang sama, kami menghemat dalam watercount_sendStr berapa banyak yang kami konsumsi selama sebulan terakhir.

Buat penghitung string pengirim - dimulai pada cron pada hari ke-24 pukul 23.00. Cek apakah pengiriman otomatis diaktifkan, jika aktif - helm mengirim konter ke surat perusahaan pelayaran. Ternyata saya memiliki hari ke-24 sepanjang hari, sesuatu untuk diperbaiki atau hanya mengurangi pengiriman otomatis, jika terjadi kesalahan pada telegram.

Perbarui dengan komentar . Putar katup- Aturan untuk menutup / membuka keran sebulan sekali agar tidak mendidih. Tanggal 25 jam 5 pagi - agar tidak masuk ke mesin pencuci piring atau mesin cuci, tetapi bahkan jika itu sampai di sana - itu tidak kritis, tumpang tindih air akan sekitar 3-4 detik.

Dan hanya di sini rumah pintar dimulai ...
Menggabungkan sistem dalam satu titik (openhab) memungkinkan Anda untuk membangun logika yang tidak tersedia untuk satu set sistem otonom. Misalnya: peristiwa peningkatan meter air telah tiba - sistem keamanan aktif, kunci pintu depan ditutup, konsumsi energi mesin pencuci piring dan mesin cuci kurang dari 5 watt, yang berarti kebocoran telah terdeteksi oleh sensor. Kami membentuk perintah untuk menutup crane, mengirim pesan ke bot di Telegram. Tapi ini seperti utas nanti.

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


All Articles