ربط Aquastorozh إلى المنزل الذكي على Z- الموجة



في العام الماضي ، اشتريت معدات للإغلاق الطارئ للرافعات عند اكتشاف تسرب من Aquastorozh. لفترة طويلة لم أتمكن من وضعه. كانت هناك فكرة لدمجها في شبكة Z-Wave والحصول على تناظرية gidrolock ، ولكن العمل على البطاريات. وأخيرا ، وصلت اليدين ...

Aquastorozh هو قاعدة مع المكونات في الصنابير وأجهزة استشعار التسرب. يمكن أن يعمل هذا المجمع من شبكة 220 فولت عبر محول ومن البطاريات. وفرت للمطورين القدرة على الاتصال بأنظمة "المنزل الذكي". بإغلاق زوج من جهات الاتصال في منفذ Ethernet ، يمكنك فتح الصنابير والآخر يغلقها. يتم إغلاق جهات اتصال الترحيل لمدة ثانية واحدة عند اكتشاف تسرب. يوجد موصل UART غير ملحوم على السبورة ، لكن في هذه المقالة سأتحدث عن تنفيذ الوظائف الموثقة.

مهام التطوير


  • عن بعد على / قبالة الصنابير.
  • معلومات التسرب.
  • متران للمياه.
  • لا تقاطع عمل "Aquastorozh".

قررت أن تفعل على أساس ZUNo الدرع. يتم تسليمها في حاوية مغلقة مع ختم الضغط ، وكتل الطرفية على متن الطائرة ومساحة خالية لتركيب البطارية والمكونات الإلكترونية الإضافية. اردوينو مشابه.

موصل إيثرنت




أحد الأسلاك القابلة للإغلاق هو "الأرض" لـ "الحارس المائي". يمكنك الجمع بين أراضي ZUNo و Aqua-Watch والتحكم في الرافعات مباشرة من خلال GPIO ZUNo. هكذا فعلت. لكن في حالة حدوث عطل في ZUNo (على سبيل المثال ، نفدت البطارية) ، فإن خطوط التحكم "Aquastorozh" تحصل على "صفر" وتبدأ في إعادة التشغيل دوريًا. مثل خيار الاتصال هذا يؤثر بشكل كبير على موثوقية النظام بأكمله ، وبالتالي ، بعد أن أقحم الدائرة قليلاً ، انتقلت إلى مرحلتين من القصب ، مما وفر عزلاً جلفانياً من Aquastorozh. تستهلك المرحلات حوالي 7 مللي أمبير عند التشغيل. لتبديل الرافعات ، تحتاج إلى تشغيل مرحل واحد لثانية واحدة ، وهو أمر مقبول تمامًا. كانت شحن البطارية كافية لعدة آلاف من المحولات. (الآن لديّ ملف كهرومغناطيسي للنبض الكهرومغناطيسي ينقل واحدة على يدي. لتبديلها ، تحتاج إلى تطبيق نبضة قدرها 1 مللي ثانية ، وهي أكثر كفاءة في استخدام الطاقة. ولكن للتحكم ، تحتاج إلى 4 ترانزستورات وساقين إدخال / إخراج للتتابع).

النوم في Z- الموجة


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

تطبيق


يحتوي ZUNo Shield على لوح صغير يمكنك من خلاله وضع المكونات الضرورية.



تحتوي الدائرة على مرحلتين واثنين من الترانزستورات للسيطرة عليها. رسم بسيط بسيط.



بضع كلمات عن استهلاك الطاقة.

يحتوي ZUNo shield على شريحة برنامج تشغيل لبروتوكول RS-485 ومقاوم سحب لأعلى للدبوس "11" على الكتلة السفلية لبروتوكول One Wire. بعد إزالة هذه المكونات ، يبقى المستهلك الرئيسي هو ZUNo.



يبلغ الاستهلاك في وضع السكون حوالي 5-10 ميكرولتر ، وفي الوضع النشط يصل إلى 60 مللي أمبير (مرحل نشط و ZUNa يرسل).

تذبذبات الاستهلاك الحالي لمختلف أوضاع التشغيل


اتجاه المحور الحالي هو من أعلى إلى أسفل.

الجهاز في انتظار أمر:



تقريبًا كل ثانية تقريبًا ، تكون القمم القصيرة مرئية خلالها يستيقظ الجهاز ويتحقق مما إذا كان قد تم تشغيل حزمة الإيقاظ.

تلقى الجهاز الأمر:



أولاً ، استيقظ الجهاز ، وتلقى شعاع تنبيه ، انتظر أمرًا (من 0 إلى ثانية واحدة) ، إذا كان الأمر للتحكم في الرافعات ، فإنه يقوم بتشغيل التتابع المقابل لمدة ثانية واحدة (في هذه المرحلة ، تحتاج إلى وضع وحدة التحكم في وضع السكون مع الحفاظ على الأرجل في الحالة الحالية ، لكنني كنت خائفًا وكسولًا جدًا) وقضي باقي الوقت على التشغيل الداخلي للرقاقة ، وبعد ذلك تغفو ZUNo. ما مجموعه 3.5 ثانية تقريبًا لكل عملية فتح أو إغلاق بواسطة الصنابير. وقت طويل بشكل رهيب ، ولكن نظرًا لحقيقة أنه سيتم تنفيذ مثل هذه العمليات في حالات نادرة للغاية ، يمكن إهمال التحسين. نعم ، وهذا لن يعطي الكثير ، لأن الرسم في Arduino ide ليس سوى جزء صغير مما تم قذفه وتحويله إلى هذا المتحكم الصغير ، وما تم إخفاؤه بأمان بواسطة الشركة المصنعة من الفضوليين.

مخطط اتصال "Aquastorozh"




استنتاج


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



شكرا لاهتمامكم!

رسم
//#define _DEBUG #define OPEN_PIN 11 #define CLOSE_PIN 12 #define LEAK_PIN 19 #define INT1 18 uint8_t valve_action = 0; #ifdef _DEBUG uint8_t const METER1_PIN = 8; #else uint8_t const METER1_PIN = 7; #endif #define METER2_PIN 8 #include "EEPROM.h" #define MAGIC_VALUE 42 #define ADDR_ACTION 1 #define CH_METER_1 4 #define CH_METER_2 8 #define CNT_ON_OFF_CICL 12 // Global variables byte pin7SwitchBinaryState = 0; DWORD eeprom_buf = 0; #define LEAK_CHANNEL 3 DWORD meter_cnt1; DWORD meter_cnt2; #define ADR_MET1 4 #define ADR_MET2 5 uint8_t alarm_clr = LOW; // Z-Wave channels ZUNO_SETUP_CHANNELS( ZUNO_SWITCH_BINARY(pin7SwitchBinaryGetter, pin7SwitchBinarySetter), ZUNO_SWITCH_BINARY(alarmGetter, alarmSetter), ZUNO_SENSOR_BINARY(ZUNO_SENSOR_BINARY_TYPE_WATER, getterSensorBinary), ZUNO_METER(ZUNO_METER_TYPE_WATER, METER_RESET_ENABLE , ZUNO_METER_WATER_SCALE_PULSECOUNT, 4, 0, getterMETER1, resetterMETER1), ZUNO_METER(ZUNO_METER_TYPE_WATER, METER_RESET_ENABLE , ZUNO_METER_WATER_SCALE_PULSECOUNT, 4, 0, getterMETER2, resetterMETER2) ); ZUNO_SETUP_BATTERY_LEVELS(2700, 3300); ZUNO_SETUP_SLEEPING_MODE(ZUNO_SLEEPING_MODE_FREQUENTLY_AWAKE); void close_water() { #ifdef _DEBUG Serial1.println("close"); #endif digitalWrite(CLOSE_PIN, HIGH); delay(1000); digitalWrite(CLOSE_PIN, LOW); //delay(1000); } void open_water() { #ifdef _DEBUG Serial1.println("open"); #endif digitalWrite(OPEN_PIN, HIGH); delay(1000); digitalWrite(OPEN_PIN, LOW); //delay(1000); } #define LEAK_DETECTED LOW #define LEAK_END HIGH #define ADDR_LEAK_ST_LAST 2 #define ADR_B1_F 3 #define ADR_B2_F 4 #define NZ_ADR_LEAK 5 uint8_t last_leak_st; #define EEPROM_MAGIC 0x11223342 #define EEPROM_ADR_MAGIC 0 void setup() { #ifdef _DEBUG Serial1.begin(9600); Serial1.println("serial init"); #else pinMode(METER1_PIN, INPUT); pinMode(METER2_PIN, INPUT); #endif pinMode(CLOSE_PIN, OUTPUT); pinMode(OPEN_PIN, OUTPUT); pinMode(LEAK_PIN, INPUT_PULLUP); pinMode(INT1, INPUT_PULLUP); digitalWrite(CLOSE_PIN, LOW); digitalWrite(OPEN_PIN, LOW); byte n; NZRAM.get(0x0, &n, 1); if (n == MAGIC_VALUE) { // correct magic value after wake up from sleep mode // trust NZRAM data } else { // incorrect magic, first boot after battery insert ot rebooted due to low battery // initialize NZRAM magic n = MAGIC_VALUE; NZRAM.put(0x0, &n, 1); NZRAM.write(ADDR_ACTION, LOW); NZRAM.write(ADDR_LEAK_ST_LAST, LEAK_END); NZRAM.write(ADR_B1_F, HIGH); NZRAM.write(ADR_B2_F, HIGH); } EEPROM.get(EEPROM_ADR_MAGIC, &eeprom_buf, sizeof(DWORD)); if(eeprom_buf != EEPROM_MAGIC) { eeprom_buf = EEPROM_MAGIC; EEPROM.put(EEPROM_ADR_MAGIC, &eeprom_buf, sizeof(DWORD)); resetterMETER1(); resetterMETER2(); eeprom_buf = 0; EEPROM.put(CNT_ON_OFF_CICL, &eeprom_buf, sizeof(DWORD)); } } uint8_t last_btn_st; void check_btn(uint8_t meter_pin, uint8_t NZ_adr_st) { last_btn_st = NZRAM.read(NZ_adr_st); if(digitalRead(meter_pin) == LOW) { if(last_btn_st != LOW) { for(uint8_t i=0; i<3; ++i) { if(digitalRead(meter_pin) == LOW) delay(5); else return; } last_btn_st = LOW; NZRAM.write(NZ_adr_st, last_btn_st); } } else { if(last_btn_st == LOW) { for(uint8_t i=0; i<3; ++i) { if(digitalRead(meter_pin) == HIGH) delay(5); else return; } last_btn_st = HIGH; NZRAM.write(NZ_adr_st, last_btn_st); if(NZ_adr_st == ADR_B1_F) inc_met(ADR_MET1); else inc_met(ADR_MET2); } } } //=----------------------------------------------------------- void loop() { if(digitalRead(LEAK_PIN) == LEAK_DETECTED) { if(NZRAM.read(ADDR_LEAK_ST_LAST) != LEAK_END) { zunoSendReport(LEAK_CHANNEL); NZRAM.write(ADDR_LEAK_ST_LAST, LEAK_END); } } check_btn(METER1_PIN, ADR_B1_F); check_btn(METER2_PIN, ADR_B2_F); if(zunoGetWakeReason() == ZUNO_WAKEUP_REASON_RADIO) { uint32_t start_time=0; #define ACTION_T_OUT 2000 start_time = millis(); //while(NZRAM.read(ADDR_ACTION)== 0) while(valve_action== 0) if((millis() - start_time) >= ACTION_T_OUT) { #ifdef _DEBUG Serial1.println("T_OUT"); #endif break; } else delay(50); #ifdef _DEBUG Serial1.println(millis() - start_time); #endif if(NZRAM.read(ADDR_ACTION)) { valve_action = 0; NZRAM.write(ADDR_ACTION, LOW); if(pin7SwitchBinaryState == LOW) close_water(); else open_water(); } if(alarm_clr) //      { alarm_clr == LOW; zunoSendReport(LEAK_CHANNEL); } } if(digitalRead(INT1)==0) { zunoSetWUOptions(ZUNO_WUPFLAGS_INT1_HIGH); } else { zunoSetWUOptions(ZUNO_WUPFLAGS_INT1_LOW); } zunoSendDeviceToSleep(); } //----------------------------------------------------------- // Getters and setters void inc_met(uint8_t num_chennel) { uint8_t eeprom_adr_met; if(num_chennel == ADR_MET1) eeprom_adr_met = CH_METER_1; else eeprom_adr_met = CH_METER_2; EEPROM.get(eeprom_adr_met, &eeprom_buf, sizeof(DWORD)); eeprom_buf++; EEPROM.put(eeprom_adr_met, &eeprom_buf, sizeof(DWORD)); zunoSendReport(num_chennel); } DWORD getterMETER1() { EEPROM.get(CH_METER_1, &eeprom_buf, sizeof(DWORD)); return eeprom_buf; } DWORD getterMETER2() { EEPROM.get(CH_METER_2, &eeprom_buf, sizeof(DWORD)); return eeprom_buf; } void resetterMETER1() { eeprom_buf = 0; EEPROM.put(CH_METER_1, &eeprom_buf, sizeof(DWORD)); } void resetterMETER2() { eeprom_buf = 0; EEPROM.put(CH_METER_2, &eeprom_buf, sizeof(DWORD)); } void pin7SwitchBinarySetter(byte value) { valve_action = 1; NZRAM.write(ADDR_ACTION, HIGH); pin7SwitchBinaryState = value; if(value == 255) // if open valve, then off leak alarm { NZRAM.write(ADDR_LEAK_ST_LAST, LOW); zunoSendReport(LEAK_CHANNEL); } } byte pin7SwitchBinaryGetter() { return pin7SwitchBinaryState ? 0xFF : 0; } byte getterSensorBinary() { return digitalRead(LEAK_PIN) ? 0 : 0xFF; } byte alarmGetter() { uint8_t ret; ret = NZRAM.read(ADDR_LEAK_ST_LAST); return ret ? 0xFF : 0; } void alarmSetter(byte value) { alarm_clr = HIGH; NZRAM.write(ADDR_LEAK_ST_LAST, value); } 

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


All Articles