Gerenciamento de energia em casa inteligente, fácil de usar e confiável: Domoticz + interruptor manual

Oi Geektimes!

Estou implementando minha casa inteligente e quero compartilhar algumas soluções conquistadas com muito esforço.

Como controlador central na minha versão da casa inteligente, uso o Raspberry Pi com o Mosqito, o Domoticz e o MQTT broker instalados. O controlador central gerencia uma variedade de cargas, muitas vezes localizadas bem longe do edifício principal, por exemplo, em uma garagem ou em uma estufa. Nesses locais remotos, uso relés KMTronic UDP de baixo custo para alternar cargas e o Arduino com Ethernet Shield para coleta e feedback de dados.

Além disso, prefiro usar o esquema de comutação para que, a qualquer momento, inclusive quando os elementos da infraestrutura de casa inteligente falhem, eu possa alternar as cargas manualmente. Para mim, o requisito de confiabilidade é secundário - o principal é que minha esposa sempre mantenha a interface de gerenciamento familiar, o que me permitirá manter a paz em minha família e me dará a oportunidade de continuar a perseguir meus hobbies favoritos.

Idéia


A idéia é simples: a aplicação do circuito de comutação clássico a partir de dois locais:



O comutador SA1 é uma das saídas de relé KMTronic (NO-C-NC), o comutador SA2 é um comutador de chave única doméstico comum. Tudo funciona bem, mas há uma ressalva - o controlador não possui informações sobre o estado real da carga. Não importa - adicione um relé intermediário ou um contator KM com uma bobina de 24V ao circuito como uma carga:


assim, mataremos vários coelhos com uma cajadada:
  • tenha a oportunidade de usar contatos de retransmissão adicionais do KM para obter feedback;
  • aumentaremos a segurança elétrica, o que é especialmente importante em salas úmidas;
  • poderemos alternar cargas mais poderosas do que as projetadas para os relés KMTronic.

Como relés intermediários, gosto de usar o Hager ERxxxx em 24V com controle manual forçado (OFF, AUTO, ON).



Esta opção ajuda muito durante a depuração e mais operações.

Implementação


Conexão de relé KMTronic UDP ao Domoticz no Raspberry Pi



  • Defina o socat para trabalhar com o UDP:

    sudo apt-get install socat
    

  • No diretório ~ / domoticz / scripts, crie um script para controlar o KMTronic via UDP. Chame o script, por exemplo, 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
    

  • Tornamos o arquivo rudp.sh executável:

    chmod +x rudp.sh
    

  • Verifique na linha de comando:

    rudp.sh 199 1
    


    Este comando deve alternar o relé nº 1 do dispositivo KMTronic com o endereço 192.168.100.199 usando a porta padrão 12345.

  • No Domoticz, crie uma opção Dummy, nos campos Em Ação e Fora de Ação, especifique:

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


    Agora, quando você clica no comutador, o contato de retransmissão UDP é alternado.
    Em paralelo, podemos alternar a carga usando o interruptor manual.


Coleta de informações sobre o estado das cargas usando o protocolo MQTT do Arduino


  • Nós preenchemos o esboço para trabalhar com o MQTT no Arduino (atenção, no esboço você precisa conectar as entradas do Arduino e os índices Idx de nossos comutadores Dummy, preenchendo a matriz domoticz_Idx []).
    Esboço
    #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]; 
        }
      }    
    }
    


  • Conectamos um contato livre do nosso relé intermediário aos contatos Gnd e DIxx do Arduino.

  • Para receber informações por meio do MQTT no Domoticz, instale o MQTTWorker.

  • Ligue e desligue manualmente a carga e observe a mudança no estado de carga na interface Domoticz.


Obrigado por sua atenção, espero que alguém ache minha experiência útil.

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


All Articles