Conectando Aquastorozh a Smart Home en Z-Wave



El año pasado, compré equipos para el cierre de emergencia de grúas cuando se detectó una fuga de Aquastorozh. Durante mucho tiempo no pude decirlo. Hubo una idea para integrarlo en la red Z-Wave y obtener un análogo de gidrolock, pero funcionaba con baterías. Finalmente, las manos llegaron ...

Aquastorozh es una base con grifos enchufables y sensores de fugas. Este complejo puede funcionar tanto desde una red de 220 V a través de un adaptador como desde baterías. Los desarrolladores han proporcionado la capacidad de conectarse a los sistemas de "hogar inteligente". Al cerrar un par de contactos en una salida de Ethernet, puede abrir los grifos y el otro cerrarlos. Los contactos del relé se cierran durante 1 segundo cuando se detecta una fuga. Hay un conector UART no soldado en la placa, pero en este artículo hablaré sobre la implementación de funciones documentadas.

Tareas de desarrollo


  • Grifos remotos de encendido / apagado.
  • Información de fugas.
  • Dos medidores de agua.
  • No interrumpa el trabajo de "Aquastorozh".

Decidió hacerlo sobre la base del escudo ZUNo. Se entrega en una caja sellada con sello de presión, tiene bloques de terminales a bordo y espacio libre para instalar la batería y componentes electrónicos adicionales. Arduino es similar.

Conector Ethernet




Uno de los cables que se pueden cerrar es la "tierra" del "vigilante acuático". Puede combinar las tierras de ZUNo y Aqua-Watch y controlar las grúas directamente a través de GPIO ZUNo. Entonces lo hice. Pero en el caso de una falla de ZUNo (por ejemplo, la batería se ha agotado), las líneas de control "Aquastorozh" reciben un "cero" y comienza a reiniciarse cíclicamente. Tal opción de conexión afecta en gran medida la confiabilidad de todo el sistema, por lo tanto, después de haber complicado un poco el circuito, cambié a dos relés de láminas, que proporcionaron aislamiento galvánico de Aquastorozh. Los relés consumen aproximadamente 7 mA cuando están encendidos. Para cambiar las grúas, debe encender un relé durante un segundo, lo cual es bastante aceptable. La carga de la batería fue suficiente para varios miles de cambios. (Ahora tengo relés de bobina simple pulsados ​​electromagnéticos en mis manos. Para cambiarlos, necesita aplicar un pulso de 1 ms, que es mucho más eficiente en energía. Pero para controlar necesita 4 transistores y dos patas de entrada / salida para el relé).

Dormir en onda Z


Hablaré un poco sobre cómo duermen los dispositivos Z-Wave y sobre el problema resultante.
Los dispositivos de onda Z pueden estar inactivos o, a menudo, despertarse. El dispositivo para dormir es el más eficiente energéticamente, pero no se le puede enviar un comando (en mi caso, para cambiar las grúas). El segundo tipo me queda bien. Dispositivo FLiRS: esclavos de enrutamiento que escuchan con frecuencia. Un dispositivo configurado para este modo de operación se activa cada segundo, y si por un corto período de tiempo no recibe una señal de activación completa del controlador, se queda dormido. Por ejemplo: envío un comando para abrir grúas. El controlador comprende que mi dispositivo a menudo está escuchando y envía un haz de activación corto especial en un segundo para que todos los dispositivos FLIRS en la red se activen. Tan pronto como mi dispositivo acepta este paquete, envía un informe de que se ha despertado y está listo para aceptar el comando. Obtiene un comando para cerrar los grifos. Quedarse dormido de nuevo. Y así, cada vez que se controla el dispositivo. La desventaja es que el dispositivo puede recibir un rayo de activación tanto al final de la transmisión por el controlador como al principio. El controlador lo envía durante aproximadamente un segundo. En el peor de los casos, el dispositivo se activa al comienzo de este boletín y esperará casi un segundo hasta que llegue un comando. Pero dado que abrir y cerrar grifos a menudo no es necesario, esto no es un inconveniente serio.

Implementación


ZUNo Shield tiene una pequeña placa de pruebas en la que puede colocar los componentes necesarios.



El circuito contiene dos relés y dos transistores para su control. Un pequeño boceto simple.



Algunas palabras sobre el consumo de energía.

El escudo ZUNo contiene un chip controlador para el protocolo RS-485 y una resistencia pull-up para el pin "11" en el bloque inferior, para el protocolo One Wire. Después de eliminar estos componentes, el principal consumidor sigue siendo ZUNo.



El consumo en modo de reposo es de aproximadamente 5-10 μA, y en modo activo de hasta 60 mA (el relé está activo y ZUNa está transmitiendo).

Oscilogramas de consumo de corriente para diferentes modos de funcionamiento.


La dirección del eje actual es de arriba a abajo.

El dispositivo está esperando un comando:



Aproximadamente cada segundo, son visibles picos cortos durante los cuales el dispositivo se activa y comprueba si ha llegado el rayo de activación.

El dispositivo recibió el comando:



Primero, el dispositivo se despertó, recibió un rayo de activación, esperó un comando (de 0 a 1 segundo), si el comando para controlar las grúas, enciende el relé correspondiente durante 1 segundo (en esta etapa debe poner el controlador en suspensión mientras mantiene las patas en el estado actual, pero yo Tenía miedo y era demasiado vago) y el resto del tiempo se dedica al funcionamiento interno del chip, después de lo cual ZUNo se queda dormido. Un total de casi 3,5 segundos por una operación de apertura o cierre mediante grifos. Un tiempo terriblemente largo, pero debido al hecho de que tales operaciones se realizarán extremadamente raramente, la optimización puede ser descuidada. Sí, y dará poco, porque el boceto en el ide Arduino es solo una pequeña parte de lo que se arroja y gira en este pequeño microcontrolador, y lo que el fabricante oculta de forma segura a los curiosos.

Esquema de conexión a "Aquastorozh"




Conclusión


Resultó agregar "Aquastorozh" con bastante precisión a la red Z-Wave existente. La principal desventaja es la falta de comentarios de Aquastorozh. En esta etapa, estoy esperando una nueva versión de la biblioteca ZUNo, en la que se reparará un error que impide que ZUNo duerma normalmente, por lo que en lugar de una foto con Aquastorozh instalado y conectado, una imagen con el proceso de depuración.



Gracias por su atencion!

Bosquejo
//#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/447616/


All Articles