إدارة طاقة منزلية ذكية موثوقة وسهلة الاستخدام: Domoticz + التبديل اليدوي

مرحبًا Geektimes!

أقوم بتطبيق منزلي الذكي وأريد مشاركة بعض الحلول التي تم الحصول عليها بشق الأنفس.

بصفتي وحدة التحكم المركزية في إصداري من المنزل الذكي ، أستخدم Raspberry Pi مع Dumicicz وسيط MQTT الوسيط Mosqito. تدير وحدة التحكم المركزية مجموعة متنوعة من الأحمال ، غالبًا ما تكون بعيدة جدًا عن المبنى الرئيسي ، على سبيل المثال ، في مرآب أو في دفيئة. في مثل هذه المواقع البعيدة ، أستخدم مرحلات KMTronic UDP غير مكلفة لتبديل الأحمال و Arduino مع Ethernet Shield لجمع البيانات والتعليقات.

علاوة على ذلك ، أفضل استخدام مخطط التحويل بحيث يمكنني في أي وقت ، بما في ذلك عندما تفشل عناصر البنية التحتية للمنزل الذكي ، تبديل الأحمال يدويًا. بالنسبة لي ، فإن متطلبات الموثوقية ثانوية - الشيء الرئيسي هو أن زوجتي تحافظ دائمًا على واجهة الإدارة المألوفة ، والتي ستسمح لي بالحفاظ على السلام في عائلتي وإعطائي الفرصة لمواصلة ممارسة هوايتي المفضلة.

فكرة


الفكرة بسيطة: تطبيق دائرة التبديل الكلاسيكية من مكانين:



مفتاح SA1 هو أحد مخرجات مرحل KMTronic (NO-C-NC) ، ومفتاح SA2 هو مفتاح أحادي المفتاح منزلي عادي. كل شيء يعمل بشكل جيد ، ولكن هناك تحذير واحد - لا تحتوي وحدة التحكم على معلومات حول الحالة الفعلية للحمل. لا يهم - قم بإضافة مرحل وسيط أو موصل KM مع ملف 24V إلى الدائرة كحمل:


لذلك سنقتل العديد من الطيور بحجر واحد:
  • الحصول على فرصة لاستخدام جهات اتصال إضافية لترحيل KM للحصول على تعليقات ؛
  • سنزيد السلامة الكهربائية ، وهو أمر مهم بشكل خاص في الغرف الرطبة ؛
  • سوف نكون قادرين على تبديل الأحمال الأكثر قوة من تلك المصممة لمرحلات KMTronic.

بصفتي مرحلات وسيطة ، أحب استخدام Hager ERxxxx على 24V مع التحكم اليدوي القسري (OFF ، AUTO ، ON).



يساعد هذا الخيار كثيرًا أثناء تصحيح الأخطاء والتشغيل الإضافي.

التنفيذ


اتصال KMTronic UDP Relay إلى Domoticz على Raspberry Pi



  • تعيين socat للعمل مع UDP:

    sudo apt-get install socat
    

  • في الدليل ~ / domoticz / scripts ، قم بإنشاء برنامج نصي للتحكم في KMTronic عبر UDP. قم باستدعاء البرنامج النصي ، على سبيل المثال ، 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
    

  • نجعل ملف rudp.sh قابل للتنفيذ:

    chmod +x rudp.sh
    

  • تحقق من سطر الأوامر:

    rudp.sh 199 1
    


    يجب أن يقوم هذا الأمر بتبديل التتابع رقم 1 لجهاز KMTronic بالعنوان 192.168.100.199 باستخدام المنفذ الافتراضي 12345.

  • في Domoticz ، قم بإنشاء مفتاح وهمي ، في الحقلين On Action و Off Action ، حدد:

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


    الآن ، عند النقر فوق المفتاح ، يتم تبديل جهة اتصال ترحيل UDP.
    في موازاة ذلك ، يمكننا تبديل الحمل باستخدام المفتاح اليدوي.


جمع معلومات عن حالة الأحمال باستخدام بروتوكول Arduino MQTT


  • نملأ الرسم للعمل مع MQTT في Arduino (الانتباه ، في الرسم البياني ، تحتاج إلى توصيل إدخالات Arduino ومؤشرات Idx لمفاتيح Dummy الخاصة بنا عن طريق ملء مجموعة domoticz_Idx []).
    رسم
    #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]; 
        }
      }    
    }
    


  • نقوم بتوصيل اتصال مجاني لترحيلنا الوسيط بجهات الاتصال Gnd و DIxx من Arduino.

  • لتلقي المعلومات من خلال MQTT في Domoticz ، قم بتثبيت MQTTWorker.

  • قم بتشغيل وإيقاف الحمل يدويًا ولاحظ التغيير في حالة التحميل في واجهة Domoticz.


شكرا لاهتمامكم ، آمل أن يجد شخص ما تجربتي مفيدة.

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


All Articles