Manajemen daya rumah pintar yang ramah pengguna yang andal: Domoticz + saklar manual

Hai Geektimes!

Saya menerapkan rumah pintar saya dan ingin berbagi beberapa solusi yang sulit.

Sebagai pengendali utama dalam versi rumah pintar saya, saya menggunakan Raspberry Pi dengan broker Domoticz dan MQTT Mosqito yang diinstal. Pengontrol pusat mengelola berbagai muatan, seringkali terletak cukup jauh dari bangunan utama, misalnya, di garasi atau di rumah kaca. Di situs terpencil seperti itu, saya menggunakan relay UDP KMTronic yang murah untuk mengalihkan beban dan Arduino dengan Ethernet Shield untuk pengumpulan data dan umpan balik.

Selain itu, saya lebih suka menggunakan skema switching sehingga kapan saja, termasuk ketika elemen-elemen infrastruktur rumah pintar gagal, saya bisa mengganti beban secara manual. Bagi saya, persyaratan keandalan adalah sekunder - yang utama adalah istri saya selalu memelihara antarmuka manajemen yang akrab, yang akan memungkinkan saya untuk menjaga kedamaian dalam keluarga saya dan memberi saya kesempatan untuk terus mengejar hobi favorit saya.

Ide


Idenya sederhana: penerapan sirkuit switching klasik dari dua tempat:



Switch SA1 adalah salah satu output relai KMTronic (NO-C-NC), switch SA2 adalah switch single-key rumah tangga biasa. Semuanya berfungsi dengan baik, tetapi ada satu peringatan - controller tidak memiliki informasi tentang keadaan beban yang sebenarnya. Tidak masalah - tambahkan relay perantara atau kontaktor KM dengan kumparan 24V ke sirkuit sebagai beban:


Jadi kami akan membunuh beberapa burung dengan satu batu:
  • dapatkan kesempatan untuk menggunakan kontak relai KM tambahan untuk umpan balik;
  • kami akan meningkatkan keamanan listrik, yang sangat penting di kamar basah;
  • kita akan dapat mengganti beban yang lebih kuat daripada yang dirancang untuk relay KMTronic.

Sebagai relay antara, saya suka menggunakan Hager ERxxxx pada 24V dengan kontrol manual paksa (OFF, AUTO, ON).



Opsi ini banyak membantu selama debugging dan operasi lebih lanjut.

Implementasi


Koneksi Relay UDP KMTronic ke Domoticz di Raspberry Pi



  • Setel socat untuk bekerja dengan UDP:

    sudo apt-get install socat
    

  • Di direktori ~ / domoticz / scripts, buat skrip untuk mengontrol KMTronic melalui UDP. Panggil skrip, misalnya, rudp.sh:

    #!/bin/bash
    RelayIP="$1"
    RelayNumber="$2"
    Status=$(echo FF0000 | socat - udp-datagram:192.168.100.${RelayIP}:12345)
    StatusBit=${Status:RelayNumber-1:1}
    CommandON=FF0${RelayNumber}01
    CommandOFF=FF0${RelayNumber}00
    if [ "$StatusBit" = "1" ]; then
    echo ${CommandOFF} | socat - udp-datagram:192.168.100.${RelayIP}:12345
    else
    echo ${CommandON} | socat - udp-datagram:192.168.100.${RelayIP}:12345
    fi
    

  • Kami membuat file rudp.sh dapat dieksekusi:

    chmod +x rudp.sh
    

  • Periksa dari baris perintah:

    rudp.sh 199 1
    


    Perintah ini harus mengganti relai # 1 perangkat KMTronic dengan alamat 192.168.100.199 menggunakan port default 12345.

  • Di Domoticz, buat sakelar Dummy, di bidang Aksi dan Tidak Aktif, tentukan:

    script:///home/pi/domoticz/scripts/rudp.sh 199 1
    


    Sekarang, ketika Anda mengklik sakelar, kontak Relay UDP beralih.
    Secara paralel, kita bisa mengganti beban menggunakan saklar manual.


Pengumpulan informasi tentang keadaan beban menggunakan protokol Arduino MQTT


  • Kami mengisi sketsa untuk bekerja dengan MQTT di Arduino (perhatikan, dalam sketsa Anda perlu menghubungkan input Arduino dan indeks Idx dari switch Dummy kami dengan mengisi larik domoticz_Idx []).
    Sketsa
    #include <SPI.h>
    #include <Ethernet.h>
    #include <Bounce2.h>
    #include <PubSubClient.h>
    
    byte mac[]    = {  0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
    byte server[] = { 192, 168, 100, 250};
    byte ip[]     = { 192, 168, 100, 199};
    
    // I/O ports on board, 20 for UNO and Leonardo (14 DI + 6 AI) 
    static const int ioPorts = 20; 
    
    // all pins                           0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19
    static const uint8_t arduinoPins[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,A0,A1,A2,A3,A4,A5};
    static const int availablePin[]    = {1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1}; //  pins available for general I/O. 1 - available, 0 - not available
    static const int domoticz_Idx[]    = {5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; //
    
    // Buffers for sending data
    char  statusBuffer[ioPorts+1] = "0";           
    char  prevStatusBuffer[ioPorts+1] = "0"; 
    
    // Instantiate a Bounce object
    Bounce debouncer[ioPorts] = Bounce();
    
    // Function headers
    void callback(char* topic, byte* payload, unsigned int length);
    char pinToChar(int value);
    int compareCharArrays(char  array1[ioPorts+1], char array2[ioPorts+1]);
    void readAllPins();
    void publishPins(boolean all);
    void setup();
    void loop();
    
    EthernetClient ethClient;
    PubSubClient clientMQTT(server, 1883, callback, ethClient);
    
    void callback(char* topic, byte* payload, unsigned int length) {
      byte* p = (byte*)malloc(length);
      memcpy(p,payload,length);
      publishPins(true); 
      free(p);
    }
    
    char pinToChar(int value) {
      char result = 'X';
      if (value==HIGH) {
        result = '0';  // if pin opened, send 0
      }  
      if (value==LOW) {
         result = '1';  // if pin closed to GND, send 1
      }   
      return result; 
    }
    
    int compareCharArrays(char  array1[ioPorts+1], char array2[ioPorts+1]) {
      int result = 0;
      for (int i =0; i <= (ioPorts); i++) {
        if (array1[i]!=array2[i]) {
          result = 1;
          break;
        }  
      }  
      return result;    
    }
    
    void readAllPins() {
      for (int i =0; i < (ioPorts); i++)
      {
        if (availablePin[i]) 
        {
          debouncer[i].update();
          statusBuffer[i] =  pinToChar(debouncer[i].read());
        }  
      }  
    }
    
    void publishPins(boolean all) {
      char topic[]="domoticz/in";
      String data;
      char jsonStr[200];
      for (int i =0; i < (ioPorts); i++)
      {
        if ((all) || (prevStatusBuffer[i]!=statusBuffer[i]))
        {
          if ((availablePin[i]) && (domoticz_Idx[i])) 
          {
            data="{\"idx\":";
            data+=(int)domoticz_Idx[i];
            data+=",\"nvalue\":";
            data+=(char)statusBuffer[i];
            data+="}";
            data.toCharArray(jsonStr,200);
            clientMQTT.publish(topic,jsonStr); 
            Serial.print(topic);
            Serial.print(" ");
            Serial.println(jsonStr);
          }
        }  
      }  
    }
    
    void setup() {  
      // initialize serial port over USB  
      Serial.begin(9600);
      
      Ethernet.begin(mac, ip);
      
      // initialize the digital pins as an input.
      for (int i =0; i < ioPorts; i++)
      {
        if (availablePin[i]) { 
          pinMode(i, INPUT_PULLUP);
          debouncer[i].attach(arduinoPins[i]);       // setup the Bounce instance
          debouncer[i].interval(100);   // interval in ms
        }  
        statusBuffer[i]='0';  
        prevStatusBuffer[i]='0'; 
      }
      statusBuffer[ioPorts]='\0';      // EOL
      prevStatusBuffer[ioPorts]='\0';  // EOL
    
      readAllPins();
      
      if (clientMQTT.connect("myhome-ino-id1")) {
        clientMQTT.subscribe("myhome/ino/id1/in/#");
        publishPins(true);
      }
    }
    
    void loop(){
      clientMQTT.loop();
      readAllPins();
      if (compareCharArrays(statusBuffer,prevStatusBuffer)==1)
      // time for send information to the server
      {
          if (!clientMQTT.connected()){
            if (clientMQTT.connect("myhome-ino-id1")) {
              clientMQTT.subscribe("myhome/ino/id1/in/#");
            }  
          } 
          
          if (clientMQTT.connected()) { 
            publishPins(false);
          }  
        
        for (int i =0; i < (ioPorts); i++) {
          prevStatusBuffer[i]=statusBuffer[i]; 
        }
      }    
    }
    


  • Kami menghubungkan kontak bebas dari relai perantara kami ke kontak Gnd dan DIxx dari Arduino.

  • Untuk menerima informasi melalui MQTT di Domoticz, instal MQTTWorker.

  • Nyalakan dan matikan beban secara manual dan amati perubahan kondisi muatan di antarmuka Domoticz.


Terima kasih atas perhatian Anda, saya harap seseorang akan menemukan pengalaman saya bermanfaat.

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


All Articles