diff --git a/ZMHW_Project_LaserDiodeSensor.ino b/ZMHW_Project_LaserDiodeSensor.ino new file mode 100644 index 0000000..fae3cdd --- /dev/null +++ b/ZMHW_Project_LaserDiodeSensor.ino @@ -0,0 +1,338 @@ +/* + * + * ZoneMinder Hardware Project + * Laser Sensor + * + * + * A sensor communicating + * via ENC28J60 to ZMTrigger daemon + * + * + */ + + +/* + * What it does: + * + * + */ + +/* + * + * + * + * Directions: + * + * Use Arduino Uno + * Connect Pin 3 to Reset pin (may not be needed) + * Connect ENC28J60 using these instructions: + * https://github.com/ntruchsess/arduino_uip + * http://web.archive.org/save/https://create.arduino.cc/projecthub/Sourcery/how-to-connect-the-enc28j60-to-an-arduino-efd0dd + * CS for ENC and UIP library is 10 by default on UNO. Not 8, like that link says. + * + * Connect microwave motion sensor such as HB100, or laser diode to A1 + * Add a speaker for audible debugging + * LED can also be added + * + * + * + * + */ + + + + +#include +#include + + + + +//Edit the below values + +#define DEBUGMODE 1 // 1 == on. 0 == off. + + +/***************Ethernet ENC28J60***************/ + +//Mac must be unique +byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xEA, 0x11 }; +//IP of Arduino +byte ip[] = { 192, 168, 1, 177 }; +//IP of zm server +byte server[] = { 192, 168, 1, 178 }; + +//ZM server ip to put in requests. +//maybe you can use hostname, not sure. TODO: test hostnames +String host="192.168.1.178"; + +//username and password to login to Zoneminder Server. +//If you don't have authentication, you will need to edit the +//script. +//NOTE: not needed for ZMTrigger. Only API. +String username="username"; +String password="password"; + +EthernetClient client; + + +#define ZMTRIGGERPORT 6802 + + + + +/***************Pins***************/ + +#define SPEAKER_PIN 6 +#define LED_PIN 9 +#define RESETPIN 2 //may not be needed here +#define SENSORPIN A1 + + + + +/***************Variables************/ + +int MotionSensorRead = 0; +uint8_t AlarmActive = 0; +char* ZMTriggerMessage = "1234567890123456789012345678901234"; //Initialize this with dummy data + + + +// Upper and lower limit for ADC to register motion +// The HB100 outputs a wave that chaotically moves up and down. If the wave reaches a +// high or low point, we register an alarm. + +// These should be tuned depending on your setup and how sensitive you want motion detected +// without getting false alarms. Easiest to test with Serial output + +#define UPPERLIMIT 900 +#define LOWERLIMIT 100 + + + + +/* + + ZMTrigger Command to Send + +B|B|B|B|B|B +which in this code is: +monnum | onoff + timealarm | score | source + +e.g. +2|on+5|100|ZoneAVR|| + +This will send a command to ZMTrigger.pl to turn monitor #2 ON (alarm state) for five seconds, with a score of 100 +and the source of ZoneAVR. The text field, and show text are not setup here. + +*/ + + +char* monnum = "25"; //monitor number +char* onoff = "on"; //command to send to zmtrigger. +char* timealarm = "10"; //time to set monitor to alarm +char* score = "100"; //score to assign +char* source = "ZMHW MotionSensor"; //source + + + + +//Do not need to edit below + + + + + + + +void chime(int freq){ + tone(SPEAKER_PIN, freq, 50); + delay(50); +} + +void chimefast(int freq, int fast){ + tone(SPEAKER_PIN, freq, fast); + delay(fast); +} + +//timer/interrupt +uint16_t timer1; +uint16_t timer1_counter; +uint8_t debouncetime; +uint8_t first_interrupt = 0; + +//timer for debounce +ISR(TIMER1_OVF_vect){ + timer1++; + + if (first_interrupt == 1 ){ + debouncetime++; + } + + if (debouncetime > 2) { + first_interrupt = 0; + debouncetime = 0; + AlarmActive = 0; + } + +} + + + +void setup() +{ + + Serial.begin(9600); + Serial.println("ZMHW Project"); + Serial.println("Motion Sensor"); + + pinMode(SENSORPIN, INPUT); + pinMode(SPEAKER_PIN, OUTPUT); + pinMode(RESETPIN, OUTPUT); + + + + Ethernet.begin(mac, ip); + + + + //timer 1, setup + //Crystal of Uno is == Mega (16MHz) + + + //this timer is all bodged up, but doesn't matter, as we only + //need two or three counts between alarms. Not going to fix atm. + //and it works. + + //Clear existing registers + TCCR1A = 0; + TCCR1B = 0; + + // Set timer1_counter to the correct value for our interrupt interval + //timer1_counter = 10000; // 62500 for one second if using 256 prescaler. can't be over 16 bit value (timer1 is 16bit limited) + //timer1_counter = 10; + //TCNT1 = timer1_counter; // TCNT1 is what we are overflowing on + TCCR1B |= (1 << CS12); // 256 prescaler (divide 16mhz/256 = 62500) + TCCR1B |= 00000101; // https://web.archive.org/web/20170707164930/http://www.avrbeginners.net:80/architecture/timers/timers.html + // search tccr1b + TIMSK1 |= (1 << TOIE1); // enable timer overflow interrupt (if goes over timer, interrupt flagged) + //end timer1 + + + + sei(); //timer needs interrupts, enable interrupts + + tone(SPEAKER_PIN, 1000, 200); + delay(100); + tone(SPEAKER_PIN, 2000, 200); + delay(100); + tone(SPEAKER_PIN, 2200, 200); + delay(100); +} + + + +void loop() +{ + + + //The SICK infrared laser requires a transistor to output + //high or low, but we will cheat and instead, put it through + //a serial diode, and then use the ADC instead of a digital pin + //saves a few seconds to put a diode on the end instead of transistor + + + MotionSensorRead = analogRead(SENSORPIN); + Serial.print("Motion Sensor Value: "); + Serial.println(String(MotionSensorRead)); + //Serial.println(String(timer1)); + + if(DEBUGMODE){ + delay(10); + } + + + //upon boot, values are around 400 sometimes, so only alert at higher + if (MotionSensorRead > 500 && AlarmActive == 0){ + Serial.println("Motion Detected"); + + //firstpacketsend = 0; + + cli(); + //some of this may be redundant, need to check + AlarmActive = 1; + first_interrupt = 1; + debouncetime = 0; + sei(); + + //Want the chime to be only noticeable if you know what to listen + //for. Make it a high freq. sound that is easy to miss. + chime(13000); + + + Serial.println("Connecting..."); + + + if (client.connect(server, ZMTRIGGERPORT)) { + + chime(13000); + + + + //beware that the buffer in snprintf is big enough to hold everything + snprintf(ZMTriggerMessage, 56, "%s|%s+%s|%s|%s||", monnum, onoff, timealarm, score, source); + Serial.print("the TCP Packet being sent:"); + Serial.println(String(ZMTriggerMessage)); + + + client.println(String(ZMTriggerMessage)); //required + + + Serial.println("TCP packet sent to ZMTrigger"); + client.stop(); + } + else { + //NOTE: If you are not connected to the network + //the device will currently freeze up, and not timeout. + //Need to implement a watchdog. + //If you ARE connected to the network, and server is not available + //then it will timeout. + + Serial.println("Connection to ZM Server failed"); + + chime(50); + delay(100); + chime(50); + delay(100); + chime(50); + delay(100); + } + } + + + + + //disconnect + if (!client.connected()) { + client.stop(); + + } + + + + + + + + + + //write to eeprom if connection failed, and try again upon reboot + //EEPROM.write(EEPROM_RETRY, switch_pressed); + + + + + + +} //end main loop