You might ask why we would want the current to continually be going through the sensor instead of just kicking it high when the sensor is tripped. That would certainly use less power and might be less work for the circuits. This might be a good thing if your alarm is powered by a battery. The problem with this is that to disable a sensor all you would need to do is clip a wire running to the sensor and it would never be tripped. However if you are checking for the current to go low from your sensor then clipping a wire would trigger it off.
Ok, if you knew that the system was looking for the low current, then instead of clipping the wire you could just bridge the wires. Then if the sensor is tripped the current would still be going through the bridge and the monitor wouldn't know it was tripped. There is a way to deal with this problem also. Instead of just looking for a wire to go low we could look for the current going through the wire to change.
One way to do this is to have three wires and a couple of different sized resistors at the sensor. Two of the wires are the positive and ground, the last wire would be attached between the two resistors where you would measure. When the sensor is tripped the positive or ground is disconnected from the circuit and the value at the third wire changes to either very high or very low. Your monitor would measure a difference and decide that the sensor has tripped. If some one tries to cut or bridge the wires then the resistance in the circuit will still change and the monitor would signal a tripped sensor. Of course there are still ways you could defeat a sensor like this but it would take time measuring current in all of the wires and building something that would measure exactly the same. You would also have to be careful to not do anything that would cause a change in the wires while you were measuing or the monitor would think that it was tripped. Part of what you are measuring is the difference in the resistors. The resistors in the sensor wouldn't have to be different but for the different sensors you would probably want to switch them up just to make things more difficult to defeat.
There is an issues that you need to deal with in a circuit like this. It is that resistance in a circuit can change over time. If a connection becomes oxidized or the sensor wears then the value that is measured at the third wire could change. If you have hard coded the value you are going to start seeing false alarms. In our system the values will be measured at start up or when the alarm is set. Since you have different resistance in each of the different sensors you also have to deal with storing more than one value.
Below is the circuit that I have built to test my basic alarm system along with a parts list. Instead of using 2 resistors I used a potentiometer. You could probably also use one of these in your actual sensor too. The pot is basically the circuit from above only the resistance can be varied very easily which was nice for testing the initialization stuff. There are two of these sensors with the pots set at different resistance. I haven't actually tested the sensors in my current alarm system to see if they work this way but I am pretty sure that the motion sensor does and if not I will deal with it when I get there. The button is to turn the alarm off on the hardware side. And of course every alarm has to be loud and obnoxious so I added a peizo buzzer and a routine in the sketch that will make noise. I will replace this with a system to kick off the siren that is now a part of my current alarm.
Fritzing Bill of Materials:
J1 Piezo Speaker
R1 10kΩ Resistor
R3 Basic Potentiometer
R4 Basic Potentiometer
S1 Pushbutton
This is what the system might look like if you want to build it with your ardurino and a small bread board.
Then what it looks like on the proto shield on top of my Arduino.
By the way also, the proto shield came with my Arduino projects pack but the url on the board that tells how to assemble it is http://www.ladyada.net/make/pshield. It came unassembled and I had to solder it together. I love soldering ( is that weird or what ). The shield is also very cool and very useful.
The biggest thing this time is the sketch code.
/* * arduino alarm controler code * * author: Stacy Brothers * http://stacysarduino.blogspot.com */ const int MAX_CMD_LEN = 128; char cmd[MAX_CMD_LEN]; int buttonState = 0; int alarmPin = 9; int sensorVal = 0; const int ALARM_OFF = 0; const int ALARM_ON = 1; int alarmState = ALARM_ON; boolean alarmTriggered = false; int allowedError = 5; int zonePins[] = {0,2}; int zoneVal[] = {0,0}; boolean zoneTripped[] = {false,false}; const int ZONE_OFF = 0; const int ZONE_ON = 1; int zoneStatus[] = {ZONE_ON, ZONE_ON}; int zoneCount = 2; boolean connected = false; void setup() { Serial.begin(9600); // triggers on doors etc. for ( int i = 0; i < zoneCount; i++ ) { pinMode(zonePins[i], INPUT); } pinMode(13, OUTPUT); // alarm flasher pinMode(alarmPin, OUTPUT); // alarm sounder pinMode(7, INPUT); // reset alarm setupSensors(); } long pingWait = 0; // this is the counter to send the ping const long pingSend = 500000L; // when to send the ping void loop() { if ( Serial.available() != 0 ) { readln(cmd); } if (strcmp(cmd,"") == 0 && pingWait == pingSend) { Serial.println("ping"); pingWait = 0; } else if (strcmp(cmd, "pong") == 0) { connected = true; pingWait = 0; } else if (strcmp(cmd, "ping") == 0) { Serial.println("pong"); connected = true; pingWait = 0; } else if (strcmp(cmd, "reset alarm") == 0) { Serial.println("alarm reset"); alarmTriggered = false; digitalWrite( 13, LOW ); } else if (strcmp(cmd, "alarm off") == 0) { alarmState = ALARM_OFF; Serial.println("alarm turned off"); } else if (strcmp(cmd, "alarm on") == 0) { alarmState = ALARM_ON; Serial.println("alarm turned on"); } cmd[0]= NULL; // what ever the command was reset it pingWait++; // loop through the zones and make sure they are not triggered for ( int i = 0; i < zoneCount; i++ ) { if ( !zoneTripped[i] && zoneStatus[i] == ZONE_ON && alarmState == ALARM_ON ) { sensorVal = analogRead(zonePins[i]); if ( sensorVal > zoneVal[i] + allowedError || sensorVal < zoneVal[i] - allowedError ) { Serial.print("tripped zone: "); Serial.println(i); alarmTriggered = true; zoneTripped[i] = true; } } } // reset the alarm buttonState = digitalRead(7); if ( buttonState == LOW && alarmTriggered == true ) { //if ( connected ) Serial.println("alarm reset"); Serial.println("alarm reset"); alarmTriggered = false; digitalWrite( 13, LOW ); for ( int i = 0; i < zoneCount; i++ ) zoneTripped[i] = false; } if ( alarmTriggered && alarmState == ALARM_ON ) { soundAlarm(); } } // setup the base values for the sensors void setupSensors() { for ( int i = 0; i < zoneCount; i++ ) { int test1 = analogRead(zonePins[i]); delay(500); int test2 = analogRead(zonePins[i]); delay(500); int test3 = analogRead(zonePins[i]); delay(500); zoneVal[i] = ( test1 + test2 + test3 ) / 3; } } int tone = 1915; // c note... boolean flasher = false; void soundAlarm() { for (long i = 0; i < 200000L; i += tone * 2) { digitalWrite(alarmPin, HIGH); delayMicroseconds(tone); digitalWrite(alarmPin, LOW); delayMicroseconds(tone); } if ( tone == 1915 ) tone = 1700; // d note... else tone = 1915; if ( flasher ) { digitalWrite( 13, LOW ); flasher = false; } else { digitalWrite( 13, HIGH ); flasher = true; } // pause between notes delay(150); } void readln( char buffer[] ) { char c; int i = 0; int quiet = 0; while( true ) { if ( Serial.available() ) { quiet = 0; c = Serial.read(); if ( c == 13 ) { // carriage return Serial.read(); // line feed break; } buffer[i++] = c; if ( i == (MAX_CMD_LEN-1) ) break; } else { if ( quiet > 10000 ) break; quiet ++; } delay(10); // short delay } buffer[i] = NULL; }So this might look like a lot but really it isn't. The setup method contains a call to the function setupSensors. This is what I was talking about before. This function takes a couple of readings on the pots and averages them. It loops through all of the pots and stores a check value for each. I had to do the average thing because I found that sometimes the pots are at a point where they will bounce by one. So far it has only been by one but when I read the sensors in the loop I give or take 5. I can change this later if I find that I don't need 5 or if I need more. So far it looks like I need only one or two.
There is the bit for making the noise on the piezo. It will all go when I figure out how to hook up the real siren. The problem with the real siren is that the thing is built to use 12V and 500 mA. That is a way more than the arduino will push so I am going to use the rechargeable 12V on my current alarm to drive it and a big ole transistor to switch it on with input from the arduino. It might also be nice if I could figure out how to step the 12V down to use it for the arduino power.
There is a bit of code in there that I will be using to turn zones on and off and to only deal with sensors that are in specific states so that I don't have to deal with events multiple times.
I had to play with the communication between the arduino and the java application quite a bit. I want the arduino to be able to continue even if the java app isn't there so I have a flag to tell the arduino to deal with is if it is not. Both applications need to deal with timeouts in their readln routines. I have made these timeouts pretty short because we don't want to miss a sensor being tripped and if the program misses a command it will be back again soon enough to check again anyway. I made it so that the sketch would notify the java app that there was an sensor tripped when the alarm was on. The java app can reset the alarm and turn off the alarm all together. That is it.
Here is the code for the java app.
package com.stacybro.arduino; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import gnu.io.CommPortIdentifier; import gnu.io.SerialPort; /** * @author Stacy Brothers * http://stacysarduino.blogspot.com * */ public class ArduinoAlarmCtrl { static String CRLN = "" + (char)13 + (char)10; public static void main(String[] args) { InputStream input; OutputStream output; CommPortIdentifier portId = null; SerialPort port = null; try { portId = CommPortIdentifier.getPortIdentifier("COM3"); port = (SerialPort)portId.open("arduino", 4000); input = port.getInputStream(); output = port.getOutputStream(); port.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); while ( true ) { String inStr = readln(input); String outStr; System.out.println("From Arduino:|" + inStr + "|"); if ( inStr.equals("ping" ) ) { outStr = "pong" + CRLN; System.out.println("Sending:"+ outStr); output.write(outStr.getBytes()); } else if ( inStr.startsWith("zone triggered:" ) ) { String zone = inStr.replace("zone triggered:", ""); System.out.println("Alarm Triggered! zone: " + zone + " (" + inStr + ")"); // wait a while and then reset the alarm inStr = readln(input);System.out.println("From Arduino:|" + inStr + "|"); if ( inStr.equals("alarm reset")) continue; outStr = "reset alarm" + CRLN; System.out.println("Sending:"+ outStr); output.write(outStr.getBytes()); } } } catch (Exception e) { e.printStackTrace(); } finally { port.close(); } } static String readln(InputStream input) throws IOException { String inStr = ""; int quiet = 0; while ( true ) { if (input.available() > 0) { int inChar = input.read(); if ( inChar == 13 ) { // carriage return input.read(); // line feed break; } quiet = 0; inStr += (char)inChar; } else { if ( quiet > 5000 ) break; quiet ++; } try { Thread.sleep(10); } catch (InterruptedException e) { System.out.println("Interrupted"); } } return inStr; } }
The only really important thing is the readln routine in the java app.
The next things that I need to deal with is the real user interface on both the hardware side and the software side.