Unser Weihnachtsbaum zwitschert uns was! 3. Teil: Advent, Advent, der Baum brennt!

Send to Kindle

von Anja Schlenker und Mattias Schlenker

Echte Kerzen oder Lichterkette, das ist hier die Frage. Horst lässt die Weihnachstfeiertage im gemütlichen Kerzenschein erstrahlen. Trotz des festen Vorsatzes, die Kerzen nur im Beisein seiner Familie anzuzünden, gehen wir auf Nummer sicher. Falls der Postmann klingelt oder Mutti mal eben die Ente begießt und Horst doch mal unbeobachtet ist, twittert uns der Rauchmelder drohende Gefahr.

Rauchmelder sind – auch dank der Vorschrift, dass sie in Neubauten präsent sein müssen – billig, halbwegs zuverlässig und so generisch, dass irgendjemand andere sie schon so gehackt hat, dass sie mit Arduino zusammenarbeiten.

Also ab zum gelbblauen C in die FuZo und dort erstmal im Rauchmeldersortiment gestöbert: Einmal für 4,95€ Conrad CO-100VDS (online gibt es den zur Zeit für 13,95€ im Dreierpack) und für 9,95€ den hübscheren Sygonix 43117V eingepackt.

Nach dem Auspacken folgte die obligatorische Zerlegung: Beide nutzen identische Platinen und identische ICs. Fünf Euro zuviel für das Sygonix-Teil ausgegeben? Egal. Dass vermeintliches Billigglück nicht immer gut geht, zeigte mir Ingvar Kamprads „Patrull“, der so gruselig verarbeitet war, dass sich beim Entlöten gleich mal die Bahnen von der Platine lösten – ein Fall für Gelbe Tonne Plus. Und das für 6,99€!

Der ursprüngliche Plan war, einen Rauchmelder so zu belassen, wie er ist und das für den 85dB Piezo Alarm bestimmte Signal abzugreifen. Doch dieser Bastler hatte den richtigen Einfall, Datenblätter zu lesen. Denn: Neben ganz billigen Rauchmeldern gibt es etwas weniger billige, die ihren Kollegen auf 433MHz mitteilen, dass es raucht. Derselbe (oder ein abgekupferter Pin kompatibler) IC (mit 2000 Transistoren fast schon ein µC?) wird auch in den ganz billigen verbaut. In diesem Fall bleiben zwei Beinchen frei. Jener Pin 7, der dazu dient per HIGH-Pegel das Funkmodem und damit seine Kollegen zu triggern ist daher besonders interessant.

Angelötet

Wir sind daher erst einmal wie folgt vorgegangen: Den 9V-Batterieclip abgetrennt und Pinheader fürs Breadboard angelötet. Beinchen Nr. 7 der IC bekam ein grünes Kabel und ebenfalls nen Pin spendiert. Das rote Batteriekabel des Rauchmelders kam auf die +5V des Arduino, das schwarze auf Masse und das eben erwähnte grüne ohne Pulldown auf einen analogen Pin eines Arduino Uno.  Der Tests mit angekokelten Taschentüchern ergab schließlich, dass Nr. 7 nach ein paar Sekunden von 0 auf >800 springt, wenn es raucht. Da es nicht gerade elegant ist, ständig analoge Ports pollen zu müssen, entschieden wir uns dafür, Nr. 7 auf einen der (zwei spärlichen) Interrupts des Uno zu legen, einfach per RISING. Im loop() wird nur rumgeblinkt:

int sourcePin = 13;
int sensorValue = 0;

void setup() {
  pinMode(sourcePin, OUTPUT);
  attachInterrupt(1, burning, RISING);
  Serial.begin(9600);
  Serial.println("Los geht's...");
}

void burning() {
  Serial.println("Es brennt!");
}

void loop() {
  digitalWrite(sourcePin, HIGH);
  delay(1000);
  digitalWrite(sourcePin, LOW);
  delay(2000);
}

Beim Yún und Leonardo sind die beiden Interrupts 0 und 1 vertauscht. Wird Beinchen 7 des Rauchmelder-ICs mit D3 des Arduino verbunden, ist Interrupt 0 zu verwenden. Es könnte alles so einfach sein – steckte da nicht der Teufel im Detail: Während ein Interrupt behandelt wird, können Funktionen wie delay() nicht genutzt werden. Die verwendet aber das Temboo-API! Also flugs ein Flag gesetzt, das im Minutentakt (Sie können auch kürzere Intervalle verwenden) ausgelesen und bei Bedarf getwittert wird:

void activeSleep(int cycles) {
  for (int i = 0; i < cycles; i++) { 
    if (isBurning == true) {
      int ret = tweet("Hilfe! Ich brenne!");
      isBurning = false;
      delay(120000);
      digitalWrite(ledPin, LOW);
    } else {
      delay(60000); 
    } 
  }
}

void burning() {
    digitalWrite(ledPin, HIGH); 
    isBurning = true; 
}

void setup() {
  pinMode(sourcePin, OUTPUT);
  pinMode(ledPin, OUTPUT);
  Bridge.begin();
  attachInterrupt(1, burning, RISING);
}

Im loop() wird dann statt delay() die Funktion activeSleep() mit der entsprechenden Zahl Zyklen aufgerufen. Unseren Code räumen wir noch auf, er steht dann in den nächsten Tagen bereit.

Abgeklemmt

Zunächst beließen wir den Piezo Alarmgeber an seinem Platz und konnten auch im Alarmfalle eine akustische Meldung feststellen. Nervig war allerding das minütliche „Meine Batterie ist leer!“ Gepiepe des Rauchmelders, der ganz korrekt die 5V des Arduino als nicht ausreichend monierte. Die Lösung war glücklicherweise eine mechanische: Der Piezo-Alarmgeber kann mit drei Clips und ohne Entlöten einfach und reversibel entfernt werden. Aber: Laut Datenblatt sinkt unter 6V die Erkennungsleistung, es kann daher notwendig sein, den Rauchmelder per Poti nachzujustieren! Für unser Buch bedeutet das aber im Umkehrschluß: Pinnen wir einen Arduino an einen Rauchmelder an, müssen wir darauf achten, dass unser Arduino (-Klon) mit den maximalen 9V des Batterieblocks klarkommt. Und dieser sollte so sparsam implementiert und programmiert sein, dass die Lebensdauer der Batterie kaum eingeschränkt wird.

ACHTUNG: Verlassen Sie sich NIE auf unseren gehackten, vielleicht kaputt gelöteten und mit falscher Spannung versehenen Rauchmelder. Sehen Sie ihn immer als Ergänzung zu den primitiven akustischen Meldern in Ihrer Wohnung! Wer gerne eine präzisere als die optische Messung haben möchte, sollte sich den MQ5 einmal ansehen, dabei handelt es sich um einen Gasdetektor, der auch Schwelbrände anhand der CO-Konzentration und Gaslecks erkennt.

Einstiegsbild: By Fir0002 (Own work) [GFDL 1.2 (http://www.gnu.org/licenses/old-licenses/fdl-1.2.html)], via Wikimedia Commons

Nachtrag vom 21. Dezember:

Ich hatte mit dem Yún recht viele False Positives während der Uno steigende Flanken immer korrekt erkannt hat. Daher habe ich auf Polling umgestellt und den Pin7 des Rauchmelders auf den analogen Pin 1 des Arduinos geführt. Der Sketch wurde entsprechend angepasst:

void activeSleep(int cycles) {
  for (int i = 0; i < cycles; i++) { 
    smokeValue = analogRead(smokePin); 
    if (smokeValue > 800) {
      digitalWrite(ledPin, HIGH);
      int ret = tweet("Hilfe! Es brennt!");
      delay(120000);
      digitalWrite(ledPin, LOW);
    } else {
      delay(60000); 
    } 
  }
}