Zuverlässiges benutzerfreundliches Smart Home Power Management: Domoticz + Handschalter

Hallo Geektimes!

Ich implementiere mein Smart Home und möchte einige hart erkämpfte Lösungen vorstellen.

Als zentraler Controller in meiner Version des Smart Home verwende ich Raspberry Pi mit dem installierten Domoticz- und MQTT-Broker Mosqito. Die zentrale Steuerung verwaltet eine Vielzahl von Lasten, die sich häufig weit vom Hauptgebäude entfernt befinden, z. B. in einer Garage oder in einem Gewächshaus. An solchen entfernten Standorten verwende ich kostengünstige KMTronic UDP-Relais zum Umschalten von Lasten und Arduino mit Ethernet Shield zur Datenerfassung und Rückmeldung.

Darüber hinaus bevorzuge ich die Verwendung des Vermittlungsschemas, damit ich die Lasten jederzeit manuell umschalten kann, auch wenn die Elemente der Smart-Home-Infrastruktur ausfallen. Für mich ist das Erfordernis der Zuverlässigkeit zweitrangig - die Hauptsache ist, dass meine Frau immer über die vertraute Verwaltungsoberfläche verfügt, die es mir ermöglicht, den Frieden in meiner Familie zu bewahren und mir die Möglichkeit zu geben, meine Lieblingshobbys weiter zu verfolgen.

Idee


Die Idee ist einfach: Die Anwendung der klassischen Schaltschaltung erfolgt an zwei Stellen:



Der SA1-Schalter ist einer der KMTronic-Relaisausgänge (NO-C-NC), der SA2-Schalter ist ein gewöhnlicher Haushalts-Einschlüsselschalter. Alles funktioniert einwandfrei, es gibt nur eine Nuance: Der Controller hat keine Informationen über den tatsächlichen Lastzustand. Es spielt keine Rolle - fügen Sie dem Stromkreis ein Zwischenrelais oder ein KM-Schütz mit einer 24-V-Spule als Last hinzu:


Wir werden also mehrere Fliegen mit einer Klappe schlagen:
  • die Möglichkeit erhalten, zusätzliche KM-Relaiskontakte für Rückmeldungen zu verwenden;
  • Wir werden die elektrische Sicherheit erhöhen, was besonders in Nassräumen wichtig ist.
  • Wir können leistungsstärkere Lasten schalten als für KMTronic-Relais.

Als Zwischenrelais verwende ich gerne Hager ERxxxx auf 24V mit erzwungener manueller Steuerung (AUS, AUTO, EIN).



Diese Option hilft beim Debuggen und weiteren Betrieb sehr.

Implementierung


KMTronic UDP-Relaisverbindung zu Domoticz auf Raspberry Pi



  • Stellen Sie socat so ein, dass es mit UDP funktioniert:

    sudo apt-get install socat
    

  • Erstellen Sie im Verzeichnis ~ / domoticz / scripts ein Skript zur Steuerung von KMTronic über UDP. Rufen Sie das Skript auf, z. B. 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
    

  • Wir machen die Datei rudp.sh ausführbar:

    chmod +x rudp.sh
    

  • Überprüfen Sie über die Befehlszeile:

    rudp.sh 199 1
    


    Dieser Befehl sollte das Relais Nr. 1 des KMTronic-Geräts mit der Adresse 192.168.100.199 über den Standardport 12345 schalten.

  • Erstellen Sie in Domoticz einen Dummy-Schalter. Geben Sie in den Feldern Ein Aktion und Aus Aktion Folgendes an:

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


    Wenn Sie nun auf den Schalter klicken, wechselt der UDP-Relaiskontakt.
    Parallel dazu können wir die Last mit dem Handschalter umschalten.


Sammlung von Informationen über den Ladezustand unter Verwendung des Arduino-Protokolls MQTT


  • Wir füllen die Skizze für die Arbeit mit MQTT in Arduino aus (Achtung, in der Skizze müssen Sie die Arduino-Eingänge und die Idx-Indizes unserer Dummy-Schalter verbinden, indem Sie das Array domoticz_Idx [] ausfüllen).
    Skizze
    #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]; 
        }
      }    
    }
    


  • Wir verbinden einen freien Kontakt unseres Zwischenrelais mit den Kontakten Gnd und DIxx von Arduino.

  • Installieren Sie MQTTWorker, um Informationen über MQTT in Domoticz zu erhalten.

  • Schalten Sie die Last manuell ein und aus und beobachten Sie die Änderung des Lastzustands in der Domoticz-Schnittstelle.


Vielen Dank für Ihre Aufmerksamkeit, ich hoffe, jemand wird meine Erfahrung nützlich finden.

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


All Articles