Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Manufacturing Technology >> Herstellungsprozess

Wasserleckdetektor und Ventilsteuerung

Komponenten und Verbrauchsmaterialien

Aluminiumgehäuse
× 1
Arduino UNO
× 1
Arduino Ethernet Shield 2
× 1
Netzteil
× 1
AC-Gehäuse
× 1
LED-Kit mit Widerständen
× 1
Relais (1 Dual 5V und 1 Dual 12V)
× 1
Motorisiertes Ventil
× 1
JST-Konnektoren
× 1
Wassersensor
× 1

Über dieses Projekt

Übersicht

Während eines Gesprächs mit einem Freund stellte ich fest, dass Wasserlecks ein großes Problem sind. Mein Freund musste alle Möbel in seinem Keller ersetzen, nur weil bei der Arbeit ein Rohr gebrochen war.

Dieses Projekt ähnelt dem, das ich für den Microsoft IoT-Wettbewerb veröffentlicht habe, aber dieses basiert auf Arduino, nicht auf Raspberry. Mein Standpunkt ist folgender:Anstatt viele Verantwortlichkeiten auf einer großen Plattform (wie RasPi, DragonBoard oder einem PC) zu zentralisieren, ziehe ich es vor, delegieren einfache Verantwortlichkeiten für einfache Geräte (wie Arduino und andere). Sie werden tun, was sie tun sollen, und sich optional über das Netzwerk mit anderen (einfachen oder komplexen) Geräten verbinden, um erweiterte Dienste anzubieten. Im Falle eines Netzwerkausfalls tun sie weiterhin, was sie tun sollen.

Grundsätzlich überwacht es Wasserleckagen und löst je nach erkanntem Fehler Aktionen wie das Schließen des Hauptwassereintritts aus.

Es veröffentlicht auch Nachrichten an einen MQTT-Broker. Die Idee ist, dass das Gerät das Wasser lokal verwalten muss, aber zusammen mit anderen Geräten auch an einem größeren System beteiligt ist, das die Hausautomation verwaltet.

So sieht es aus:

Der Hauptwassereintritt befindet sich unten. Das erste Gerät wird von städtischen Wasserversorgungsunternehmen installiert, um den Wasserdruck zu kontrollieren. Ich habe das Teil oben auf dem Bild installiert. Das motorisierte Ventil (in blau) wird parallel zu einem manuellen Ventil installiert. In dieser Zeichnung ist das Handventil geöffnet und somit das Motorventil umgangen. Es ist nützlich bei Stromausfall. Im Normalbetrieb muss das Handventil ausgeschaltet sein.

Im Ventil befindet sich ein Gleichstrommotor (12 V), der sich je nach Polarität im oder gegen den Uhrzeigersinn dreht. Es gibt eine Rückkopplungsschleife, die anzeigt, ob das Ventil effektiv ein- oder ausgeschaltet ist. Um es einzuschalten, legen Sie einfach eine positive Spannung an den oberen linken Anschluss an.

Hier ist der Controller:

Von links nach rechts:der AC-Stecker, eine Reset-Taste, einige LEDs zur Statusanzeige, Anschlüsse (zu Sensoren, zum Motor), eine Ethernet- und eine USB-Schnittstelle.

  • LED1 :Rot leuchtend =Wasser lokal erkannt, Rot blinkend =Wasser aus der Ferne erkannt, Aus =kein Wasseraustritt
  • LED 2 :Gelbes Dauerlicht =Motorventil kann nicht gesteuert werden, Gelbes Blinken =MQTT-Broker nicht erreichbar, Aus =alles gut
  • LED3 :Blaues Dauerlicht =alles in Ordnung, Blaues Blinken =Motorventil ist geschlossen Aus =System ist ausgefallen oder wird nicht mit Strom versorgt

Hier ist ein Sensor, der sich dort befindet, wo ich denke, dass Wasser austreten könnte:

Hier ist das, was unter der Haube steckt:

WARNUNG!

Das AC/DC-Netzteil, das ich verwende, hat zwei Ausgänge:Der erste ist 12 V DC und wird verwendet, um das motorisierte Ventil zu speisen (gesteuert von zwei Relais, die die Motordrehung steuern) und der zweite ist GENAU 5 V DC, um die Arduinos. Deshalb füttere ich direkt den 5V-Stromkreis, nicht den Vin, der mindestens 6V DC benötigt. Sobald der AC/DC angeschlossen ist, sollten Sie NIEMALS (ich sagte NIE) weder die Arduino DC-Buchse noch das Arduino USB-Kabel anschließen. Wenn Sie immer noch über USB debuggen möchten, richten Sie ein selbstgebautes Kabel OHNE die Stromleitungen ein, behalten Sie nur die Datenleitungen bei. Die Verbindung zwischen AC-Gehäuse und AC/DC-Netzteil beträgt übrigens 110V. Nicht berühren, niemals!

Code

  • Wasserleckerkennung und motorisierte Ventilsteuerung
  • MQTT-Bibliothek
Wasserleckerkennung und motorisierte VentilsteuerungArduino
#include #include #include #include #include #include #include /* So funktioniert die HWEs gibt drei Subsysteme:- die Hauptbox:- ein Arduino Uno mit und Ethernet-Schild - eine rote LED:leuchtet, wenn Wasser lokal erkannt wird, blinkt, wenn Wasser aus der Ferne erkannt wird, ansonsten aus - eine gelbe LED:Dauerlicht, wenn das Ventil außer Betrieb ist, blinkt, wenn MQTT-Broker nicht erreichbar ist (aus irgendeinem Grund), ansonsten aus - eine blaue LED:Dauerlicht, wenn das Ventil geöffnet ist und das System Leckagen überwacht, blinkt, wenn das Ventil ausgeschaltet wurde das System ist ausgefallen - eine Drucktaste:nach dem Drücken wird ein Selbsttest ausgelöst - ein Doppelrelais zur Steuerung eines motorisierten Fernventils - ein weiteres Doppelrelais zur Erkennung der auf dem Fernventil installierten Endschalter zum Öffnen/Schließen - ein Satz Wasser Detektoren (alle parallel) (alle 3 Anschlüsse an der Frontplatte sind parallel verbunden)Das motorisierte Ventil hat die folgenden Anschlüsse:- Gelb und B lue :Gleichstrom zur Stromversorgung des Motors - Schwarz :Endschaltereingang (wird in unserer Schaltung auf GND gesetzt) ​​- Rot =wird auf GND umgeschaltet, wenn das Ventil seine vollständig geschlossene Position erreicht (Hinweis:aufgrund der internen Konstruktion des Endschalters , es gibt keine Garantie, dass die Kontinuität nach dem Ausschalten des Ventils erhalten bleibt) - Grün =wird auf GND umgeschaltet, wenn das Ventil seine vollständig geöffnete Position erreicht (Hinweis:Aufgrund der internen Konstruktion des Endschalters gibt es keine Garantie für Kontinuität bleibt, wenn das Ventil ausgeschaltet ist)*/// Networkbyte mac[] ={ 0xDE, 0xAD, 0xBE, 0xCF, 0xFC, 0xEE }; // Arduinos MAC-AdresseIPAddress ip(192, 168, 12, 215); // Arduinos IP-AdresseIPAddress-Server (192, 168, 12, 130); // Adresse des MQTT-BrokersEthernetClient ethClient;// MQTT PubSubClient client(ethClient); #define mqttClientPrefix "GLX" // Präfix zur Verwendung von MQTT-Veröffentlichungen/-Abonnements #define mqttClientLocation "BASEMENT" // Zweiter Teil der Client-ID#define mqttClientUID "001" // Letzter Teil der Client-ID#define mqttClientStatusTopic "Status" // Thema zum Veröffentlichen des Gerätestatus #define mqttClientFaultTopic "Fault" // Thema zum Veröffentlichen/Abonnieren von Faultsconst int mqttInterval =20; // bestimmt, wie oft das System an den MQTT-Broker berichtet (dh jedes mqttInterval * mainLoopDelay ms )int mqttIntervalCnt =0; // lokale Variable, die zum Herunterzählen verwendet wirdint isConnectedToBroker =-1; // 1 wenn verbunden, -1 =unbekannt, 0 =keine Verbindung möglich // Pin-outconst int SystemLedPin =A0; // Blaue LED const int FaultLedPin =A1; // Gelbe LED const int AlarmLedPin =A2; // Rote LED const int WaterDetectorPin =2; // geht auf LOW, wenn Wasser erkannt wird, ansonsten auf VCCconst hochgezogen int ToggleButtonPin =3; // geht auf LOW, wenn jemand auf die Taste drückt und geht dann auf HIGH, wenn die Taste losgelassen wird, ansonsten Pulldown auf GNDconst int SdCardPin =4; // SD-Karte auf Ethernet-Schild, nicht verwendetconst int ValveClosedPin =5; // geht auf LOW, wenn der Motor die geschlossene Schaltergrenze erreicht, andernfalls Pull-up auf HIGHconst Int ValveOpenedPin =6; // geht auf LOW, wenn der Motor die offene Schaltergrenze erreicht, andernfalls Pull-up auf HIGHconst int ValveControl1 =8; // um das erste Relais zu steuern, das die Stromversorgung des motorisierten Ventils steuertconst int ValveControl2 =7; // um das zweite Relais zu steuern, das die motorisierte Ventilstromversorgung steuert // Beachten Sie, dass D10, D11, D12 und D13 nicht verwendet werden, da diese Pins für die Ethernet-Abschirmung reserviert sind // WaterLeakage (local) int isWaterDetected =0; // Status gemäß der letzten guten Lesung // WaterLeakage (remote)int isWaterDetectedRemotely =0; // Status gemäß von anderen Überwachungsgeräten empfangenen Nachrichten // Motorized valveint isValveClosed =-1; // Status des motorisierten Ventils (-1 =unbekannt, 0 =geöffnet, 1 =geschlossen))const int valveTimeOut =15; // in Sekunden, maximale Zeit zum Öffnen oder Schließen von valveint isConnectedToValve =-1; // 0 wenn das System das motorisierte Ventil nicht steuern kann, 1 =verbunden, -1 =unbekannt // Manueller RESET-Tasterflüchtiger Boolescher Wert isResetRequested =0; // dieser ändert sich, wenn die Schaltfläche einen Interrupt auslöst // Logicconst int mainLoopDelay =500; // eine feste Verzögerung innerhalb der Hauptschleife, in msvoid(* resetFunc) (void) =0; // Initialisierung void setup(){ wdt_disable(); // Es ist immer gut, es zu deaktivieren, wenn es eingeschaltet war oder Sie die Initialisierungszeit benötigen Serial.begin (9600); Serial.println (F ("Beginn der Einrichtung")); // HW-Setup PinMode (SystemLedPin, OUTPUT); pinMode (FaultLedPin, AUSGANG); pinMode (AlarmLedPin, AUSGANG); pinMode (WasserdetektorPin, EINGANG); pinMode (ToggleButtonPin, INPUT); pinMode (ValveOpenedPin, INPUT); // Das 12-V-DC-Relais ist standardmäßig im Leerlauf. Der Pin ist mit der NO-Seite des Relais 1 verbunden, aber es gibt einen Pull-up. Pin ist daher standardmäßig HIGH. pinMode (ValveClosedPin, INPUT); // Das 12-V-DC-Relais ist standardmäßig im Leerlauf. Der Pin ist mit der NO-Seite des Relais 2 verbunden, aber es gibt einen Pull-up. Pin ist daher standardmäßig HIGH. pinMode (ValveControl1, OUTPUT); digitalWrite (Ventilsteuerung1, HOCH); // 5V DC Relais 1 ist standardmäßig im Leerlauf, d.h. Motor ist mit GND PinMode (ValveControl2, OUTPUT) verbunden; digitalWrite (Ventilsteuerung2, HOCH); // 5V DC Relais 2 standardmäßig im Leerlauf, d.h. Motor ist mit GND PinMode (SdCardPin, OUTPUT) verbunden; digitalWrite (SdCardPin, HOCH); // um die SD-Karte zu deaktivieren, da wir sie nicht verwenden // Selbsttest testLeds(); // Netzwerk- und MQTT-Setup client.setServer(server, 1883); client.setCallback(MQTTBrokerCallback); Ethernet.begin(mac, ip); Serial.print (F("Aktuelle IP ist:")); Serial.print (Ethernet.localIP()); Serial.print (F(" - MQTT-Broker-IP ist:")); Serial.println (Server); // Anfangs kennen wir den Status des Ventils nicht und die Endschalter sind nicht so zuverlässig. // Lassen Sie uns das motorisierte Ventil öffnen und auf den Abschluss warten. Im schlimmsten Fall, wenn es bereits geöffnet ist, wird es nur kurz auf den Endschalter treffen, wenn (openValve () ==0) { Serial.println (F ("Ventil ist geöffnet und das System überwacht jetzt")); // Es gibt andere Überwachungsgeräte im Haus, hören wir uns die Fehler an, die sie dem MQTT-Broker melden könnten SubscribeToRemoteWaterSensors(); } Else {Serial.println (F ("Ventil kann nicht geöffnet werden, System ist außer Betrieb. Bitte verwenden Sie den Rohrleitungsbypass")); }; enableInterruptOnResetButton(); Verzögerung (1500); // Hardware erlauben, sich selbst auszusortieren Serial.println (F ("Ende des Setups")); } // Main loopvoid loop () { // LEDs configureLedsWithInitialStates (); // Auf Reset-Anfrage reagieren, wenn (isResetRequested ==1) { Serial.println (F ("Jemand hat auf die Taste gedrückt, um dieses Gerät zurückzusetzen")); veröffentlichenStatus(); wdt_enable(WDTO_1S); // Watchdog aktivieren, wird in 1 Sekunde Verzögerung ausgelöst (5000); Serial.println (F("diese Nachricht sollte nie erscheinen")); } // Lassen Sie uns jetzt überprüfen, ob ein Wasserleck erkannt wurde readLocalWaterSensor (); if (isWaterDetected ==1 || isWaterDetectedRemotely ==1) { if (isValveClosed ==0){ closeValve();}; } // Auf MQTT-Broker veröffentlichen if (mqttIntervalCnt ==0) { if (isWaterDetected ==1){ publishFault();} publishStatus(); mqttIntervalCnt =mqttInterval; } Else { if (isConnectedToValve ==0) { Serial.println (F ("System ist außer Betrieb - motorisiertes Ventil kann nicht gesteuert werden. Keine Überwachung vorhanden")); aufrechtzuerhalten. Sonst {Serial.print (F(."")); } mqttIntervalCnt =mqttIntervalCnt - 1; } // Machen Sie eine Pause Verzögerung (mainLoopDelay / 2); client.loop(); // LEDs configureLedsWithFinalStates(); Verzögerung (mainLoopDelay / 2); } //// Lokale Wassersensorverwaltung //void readLocalWaterSensor () { isWaterDetected =!getDebouncedValue(WaterDetectorPin, 100, 10); Serial.print (isWaterDetected); } //// Schaltflächenverwaltung zurücksetzen //void enableInterruptOnResetButton () { isResetRequested =0; attachInterrupt (1, onResetRequested, CHANGE);}void onResetRequested(){ detachInterrupt(1); isResetRequested =1; } // Ventilöffnungssequenz verwaltenint openValve () { Serial.print (F ("Öffnungsventil ...")); // Bestätigen Sie zuerst, dass das Ventil geschlossen wurde, indem Sie den Motor zwingen, erneut kurz auf den "geschlossenen" Endschalter zu treffen (da diese Endschalter nicht so zuverlässig sind ...) setupRelays(1); if (waitForEndOfCycle(ValveClosedPin) ==0) {// jetzt versuchen wir das Ventil setupRelays(2) zu öffnen; if (waitForEndOfCycle(ValveOpenedPin) ==0) { isConnectedToValve =1; isValveClosed =0; setupRelais(0); // Leistungsrelais AUS Serial.println (F ( "")); 0 zurückgeben; } } setupRelays(0); // Leistungsrelais AUS isConnectedToValve =0; return -1;} // Verwalten Sie die Ventilschließsequenzint closeValve () { Serial.print (F ("Ventil schließen ...")); // Bestätigen Sie zuerst, dass das Ventil geöffnet war, indem Sie den Motor zwingen, erneut kurz auf den "offenen" Endschalter zu drücken (da diese Endschalter nicht so zuverlässig sind ...) setupRelays(2); if ( waitForEndOfCycle(ValveOpenedPin) ==0) { // Jetzt versuchen wir, das Ventil setupRelays(1) zu schließen; if (waitForEndOfCycle(ValveClosedPin) ==0) { isConnectedToValve =1; isValveClosed =1; setupRelais(0); // Leistungsrelais AUS Serial.println (F ("Ventil wurde ausgeschaltet. Bitte inspizieren Sie sorgfältig alle Räume und Reinigungsdetektoren")); 0 zurückgeben; } } setupRelays(0); // Leistungsrelais AUS isConnectedToValve =0; return -1;} // Richten Sie die Relais ein, um den Motor mit der richtigen Polarität zu speisen ); digitalWrite (Ventilsteuerung2, HOCH); brechen; Fall 1:// Schließzyklus digitalWrite (ValveControl1, HIGH); digitalWrite (Ventilsteuerung2, NIEDRIG); brechen; Fall 2:// Öffnungszyklus digitalWrite (ValveControl1, LOW); digitalWrite (Ventilsteuerung2, HOCH); brechen; Standard:Serial.print (F ("Unerwartetes Relais-Szenario:")); Serial.println (Szenario); digitalWrite (Ventilsteuerung1, HOCH); digitalWrite (Ventilsteuerung2, HOCH); brechen; }} // Warten Sie, bis der Endschalter vom Motor des motorisierten Ventils getroffen wird int waitForEndOfCycle(int limitSwitchPin){ int cnt =valveTimeOut; while (cnt> 0) { if (getDebouncedValue (limitSwitchPin, 10, 10) ==LOW) { return 0; } cnt =cnt - 1; Serial.print (F(."")); Verzögerung (1000); }; Serial.println(F(" - Timeout beim Schließen des Ventils erreicht. Überprüfen Sie, ob das Ventil gut mit Strom versorgt und die Kabel angeschlossen sind.")); return -1;} // Diese Routine hilft, Fehlalarme zu vermeidensint getDebouncedValue(int inputPin, int intervalInMs, int requiredConfirmations){ int Confirmations =1; int currentValue =digitalRead(inputPin); while (Bestätigungen <=erforderlichBestätigungen) { delay(intervalInMs); if (currentValue ==digitalRead(inputPin)) { Bestätigungen =Bestätigungen + 1; } sonst { Bestätigungen =1; currentValue =digitalRead(inputPin); } } return currentValue;} //// LED-Verwaltung //void configureLedsWithInitialStates(){ clearLeds(); // Neu auswerten if (isWaterDetectedRemotely ==1 || isWaterDetected ==1) { digitalWrite (AlarmLedPin, HIGH);}; if (isConnectedToValve ==0 || isConnectedToBroker ==0) { digitalWrite (FaultLedPin, HIGH);}; digitalWrite (SystemLedPin, HIGH);}void configureLedsWithFinalStates () { if (isWaterDetectedRemotely ==1) { digitalWrite (AlarmLedPin, LOW);}; if (isConnectedToBroker ==0) { digitalWrite (FaultLedPin, LOW);}; if (isValveClosed ==1) { digitalWrite (SystemLedPin, LOW);}; }void clearLeds () { DigitalWrite (AlarmLedPin, LOW); digitalWrite (FaultLedPin, LOW); digitalWrite (SystemLedPin, LOW);}void testLeds () { clearLeds (); digitalWrite (AlarmLedPin, HIGH); Verzögerung (500); digitalWrite (FaultLedPin, HIGH); Verzögerung (500); digitalWrite (SystemLedPin, HIGH); Verzögerung (500); clearLeds();}//// MQTT-bezogene Funktionen //// Eingehende MQTT-Nachrichten verarbeitenvoid MQTTBrokerCallback(char* SubscribedTopic, byte* payload, unsigned int length){ Serial.print(F("Neue Nachricht vom MQTT-Broker empfangen. Topic =")); Serial.print (subscribedTopic); String payloadAsString =(char*)payload; String realPayload =payloadAsString.substring(0,length); // sonst bekommen wir Müll, da der Puffer zwischen In und Out geteilt wird Serial.print (F (", content =")); Serial.print (realPayload); if (realPayload.indexOf("WaterDetected")> 0 &&realPayload.indexOf(mqttClientLocation) ==-1 ) // der zweite Teil des Tests ist erforderlich, um selbstausgelöste Fehler zu vermeiden { isWaterDetectedRemotely =1; } // for (int i=0;i 

Schaltpläne


Herstellungsprozess

  1. Ventile für schwieriges Absperren und Regeln
  2. Raspberry Pi Sensor- und Aktuatorsteuerung
  3. Pool-Füllkontrolle
  4. Portenta H7 Dual-Core-Debugging
  5. Universelle Fernbedienung mit Arduino, 1Sheeld und Android
  6. LCD-Animation und -Spiele
  7. Münzprüfer mit Arduino steuern
  8. Arduino-Kontrollzentrum
  9. Audiofrequenzdetektor
  10. Arduino mit Bluetooth zur Steuerung einer LED!