Gestion fiable et conviviale de l'alimentation de la maison intelligente: Domoticz + interrupteur manuel

Salut les Geektimes!

J'implémente ma maison intelligente et souhaite partager quelques solutions durement gagnées.

En tant que contrôleur central dans ma version de la maison intelligente, j'utilise Raspberry Pi avec le courtier Domoticz et MQTT installé Mosqito. Le contrôleur central gère une variété de charges, souvent situées assez loin du bâtiment principal, par exemple, dans un garage ou dans une serre. Dans ces sites distants, j'utilise des relais KMTronic UDP peu coûteux pour commuter des charges et Arduino avec Ethernet Shield pour la collecte de données et le retour d'informations.

De plus, je préfère utiliser le schéma de commutation afin qu'à tout moment, y compris lorsque les éléments de l'infrastructure de la maison intelligente échouent, je puisse commuter les charges manuellement. Pour moi, l'exigence de fiabilité est secondaire - l'essentiel est que ma femme maintienne toujours l'interface de gestion familière, ce qui me permettra de garder la paix dans ma famille et me donnera l'opportunité de continuer à pratiquer mon passe-temps préféré.

Idée


L'idée est simple: l'application du circuit de commutation classique à deux endroits:



le commutateur SA1 est l'une des sorties de relais KMTronic (NO-C-NC), le commutateur SA2 est un interrupteur domestique simple à clé unique. Tout fonctionne bien, mais il y a une mise en garde - le contrôleur n'a pas d'informations sur l'état réel de la charge. Peu importe - ajoutez un relais intermédiaire ou un contacteur KM avec une bobine 24V au circuit en tant que charge:


nous tuerons donc plusieurs oiseaux avec une pierre:
  • avoir la possibilité d'utiliser des contacts relais KM supplémentaires pour la rétroaction;
  • nous augmenterons la sécurité électrique, ce qui est particulièrement important dans les pièces humides;
  • nous pourrons commuter des charges plus puissantes que celles conçues pour les relais KMTronic.

En tant que relais intermédiaires, j'aime utiliser Hager ERxxxx sur 24V avec commande manuelle forcée (OFF, AUTO, ON).



Cette option aide beaucoup lors du débogage et des opérations ultérieures.

Implémentation


Connexion du relais UDP KMTronic à Domoticz sur Raspberry Pi



  • Définissez socat pour qu'il fonctionne avec UDP:

    sudo apt-get install socat
    

  • Dans le répertoire ~ / domoticz / scripts, créez un script pour contrôler KMTronic via UDP. Appelez le script, par exemple, 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
    

  • Nous rendons le fichier rudp.sh exécutable:

    chmod +x rudp.sh
    

  • Vérifiez à partir de la ligne de commande:

    rudp.sh 199 1
    


    Cette commande doit commuter le relais # 1 de l'appareil KMTronic avec l'adresse 192.168.100.199 en utilisant le port par défaut 12345.

  • Dans Domoticz, créez un commutateur factice, dans les champs On Action et Off Action, spécifiez:

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


    Maintenant, lorsque vous cliquez sur le commutateur, le contact du relais UDP bascule.
    En parallèle, nous pouvons commuter la charge à l'aide du commutateur manuel.


Collecte d'informations sur l'état des charges à l'aide du protocole Arduino MQTT


  • Nous remplissons l'esquisse pour travailler avec MQTT dans Arduino (attention, dans l'esquisse, vous devez connecter les entrées Arduino et les indices Idx de nos commutateurs factices en remplissant le tableau domoticz_Idx []).
    Esquisse
    #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]; 
        }
      }    
    }
    


  • Nous connectons un contact libre de notre relais intermédiaire aux contacts Gnd et DIxx d'Arduino.

  • Pour recevoir des informations via MQTT dans Domoticz, installez MQTTWorker.

  • Activez et désactivez manuellement la charge et observez la modification de l'état de charge dans l'interface Domoticz.


Merci de votre attention, j'espère que quelqu'un trouvera mon expérience utile.

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


All Articles