123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339 |
- /*
- *
- * 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 <UIPEthernet.h>
- #include <EEPROM.h>
- //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<id>|B<action>|B<score>|B<cause>|B<text>|B<showtext>
- 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
|