|
|
- /*
- *
- * ZoneMinder Hardware Project
- *
- *
- *
- * A sensor on an Arduino UNO communicating
- * via ethernet to ZMTrigger daemon for ZoneMinder
- * CCTV GNU/Linux software.
- *
- *
- */
-
-
- /*
- * What it does:
- * Works with accompanying shield to act as motion sensor
- * for Zoneminder via ZMTrigger. Shield is optional but recommended
- * as it's easier to build.
- *
- * Components:
- * ENC28J60
- * Motion Sensor (Either PIR, or microwave HFS-DC06H)
- * Microphone for Loud Noise alarms
- * LM35 Temperature Sensor
- * RGB Status LED
- * Speaker
- *
- * Power from External 12V supply, not USB!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- *
- */
-
- /*
- *
- *
- *
- * Directions:
- * Use Arduino Uno
- * See https://git.steakelectronics.com/adminguy/ZMHW_Project_InfraredDiodeSensor
- *
- * 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.
- *
- *
- *
- *
- *
- */
-
-
-
-
- #include <UIPEthernet.h>
- //#include <EEPROM.h>
-
-
-
-
- //Edit the below values
-
- #define DEBUGMODE 0 // 1 == on. 0 == off.
- #define MIC 0 // 1 == on. 0 == off.
- #define SICK 0 // set to 1 if using sick sensor (on analog pin)
- // sick sensor is a transistor activated photoelectric
- // sensor. More details below.
- #define NORMALMODECT 1 // For a digital High motion sensor.
-
- /***************Ethernet ENC28J60***************/
-
- //Mac must be unique for each sensor
- byte mac[] = { 0xD3, 0x5D, 0xBE, 0xEF, 0xEE, 0x54 };
- //Static IP of Arduino
- byte ip[] = { 192, 168, 78, 54 };
- //IP of ZM Server
- byte server[] = { 192, 168, 78, 123 };
- //ZM server IP to put in requests.
- String host="192.168.78.123";
-
- char* monnum = "2"; //monitor number
-
- char* LOCATIONOFSENSOR = "Bay 3";
-
- #define ZMTRIGGERPORT 6802
- #define LISTENPORT 80 // (port 80 is default for HTTP)
-
-
-
-
- /***************Pins***************/
-
-
- //Digital
- #define MODECTPIN 4
- #define SPEAKERPIN 6
- #define LEDPIN 9
-
-
-
- //Analog
- #define TEMPPIN A0
- #define SICKPIN A1
- #define MICROPHONEPIN A2
-
-
-
-
-
- /***************Variables************/
-
-
- uint8_t AlarmActive = 0;
- char* ZMTriggerMessage = "1234567890123456789012345"; //Initialize this with dummy data
- uint8_t TEMPERATUREVALUE = 0;
- uint8_t TEMPERATUREVALUE2 = 0;
- uint8_t SOUNDVALUE = 0;
- uint16_t MODECTVALUE = 0;
-
-
- /*
- 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* onoff = "on"; //command to send to zmtrigger.
- char* timealarm = "10"; //time to set monitor to alarm
- char* score = "77"; //score to assign
- char* source = "ZMHW"; //source. Add details as needed (e.g. Hallway sensor)
-
-
-
-
- //Do not need to edit below
-
-
-
-
-
- // Initialize the Ethernet server library
-
-
- EthernetClient client;
- EthernetServer server2 = EthernetServer(LISTENPORT);
-
- /*
- void chime(int freq){
- tone(SPEAKERPIN, freq, 50);
- delay(50);
- }
-
- void chimefast(int freq, int fast){
- tone(SPEAKERPIN, 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(F("ZMHW Project"));
- Serial.println(F("Motion Sensor"));
-
- //if sick
- pinMode(SICKPIN, INPUT);
- //if mic
- pinMode(MICROPHONEPIN, INPUT);
- //if speaker
- pinMode(SPEAKERPIN, OUTPUT);
- pinMode(MODECTPIN, INPUT);
- pinMode(TEMPPIN, INPUT);
-
- //Be careful. This sets Areg to 1.1v!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- //Used for LM35.
- analogReference(INTERNAL);
-
-
-
- Ethernet.begin(mac, ip);
- server2.begin();
- Serial.print(F("server is at "));
- Serial.println(Ethernet.localIP());
-
-
-
- //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 (set) interrupts
-
- //tone(SPEAKERPIN, 1000, 200);
- //delay(100);
- //tone(SPEAKERPIN, 2000, 200);
- //delay(100);
- //tone(SPEAKERPIN, 2200, 200);
- //delay(100);
- }
-
-
-
- void loop()
- {
- //delay(50);
-
-
-
- /*****************ANALOG SECTION******************/
-
- //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
- //when soldering by hand. Works equally as well. Requires ADC pin.
-
- /*
- if (SICK){
- MotionSensorRead = analogRead(SICKPIN);
- Serial.print("Motion Sensor Value: ");
- Serial.println(String(MotionSensorRead));
- //Serial.println(String(timer1));
- delay(30);
- }
- */
-
-
- //todo: only serial.print temp every 10 or so reads
- TEMPERATUREVALUE = analogRead(TEMPPIN);
- Serial.print(F("Temperature Value: "));
- // See resources. uses 1.1 aref, converts to celcius, then to Fareinheit.
- TEMPERATUREVALUE2 = (TEMPERATUREVALUE / 9.31)* 2 + 30;
- Serial.println(String(TEMPERATUREVALUE2));
- delay(30);
-
- /*
- if (MIC){
- SOUNDVALUE = analogRead(MICROPHONEPIN);
- Serial.print("Sound Value: ");
- Serial.println(String(SOUNDVALUE));
- delay(30);
- }
- */
- if (NORMALMODECT){
- delay(10);
- MODECTVALUE = digitalRead(MODECTPIN);
- delay(10);
- Serial.print(F("Motion Detector Value (normal): "));
- //Serial.println(String(MODECTVALUE));
- Serial.println(MODECTVALUE);
- delay(30);
- }
-
-
- if(DEBUGMODE){
- delay(10);
- }
-
-
-
-
- /****************MOTION SENSING****************/
-
-
-
- //SICK
- //Motion sensing for Sick Photoelectric sensor only
- //upon boot, values are around 400 sometimes, so only alert at higher
- if(SICK){
- if (MODECTVALUE > 500 && AlarmActive == 0){
- Serial.println(F("Motion Detected on Sick"));
-
- //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.
- //Resistors to speaker should be high
- //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(F("the TCP Packet being sent:"));
- //Serial.println(String(ZMTriggerMessage));
- client.println(String(ZMTriggerMessage)); //required
- Serial.println(F("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(F("Connection to ZM Server failed"));
-
-
- /*chime(50);
- delay(100);
- chime(50);
- delay(100);
- chime(50);
- delay(100);
- */
- }
- }
- }//end sick
-
-
-
-
-
- //Digital High Motion Sensor
- if(NORMALMODECT){
-
- if (MODECTVALUE==HIGH && AlarmActive == 0){
- Serial.println(F("Motion Detected on Normal Sensor"));
-
- //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.
- //Resistors to speaker should be high
- //chime(13000);
- delay(10);
-
-
- Serial.println(F("Connecting..."));
-
-
- if (client.connect(server, ZMTRIGGERPORT)) {
-
- //chime(13000);
- //delay(10);
-
-
- //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(F("the TCP Packet being sent:"));
- Serial.println(String(ZMTriggerMessage));
- client.println(String(ZMTriggerMessage)); //required
- Serial.println(F("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(F("Connection to ZM Server failed"));
-
- /* chime(40);
- delay(100);
- chime(60);
- delay(100);
- chime(60);
- delay(100);
- */
- }
- }
- MODECTVALUE=LOW;
- }//end normal Motion Sensor
-
-
- //disconnect
- if (!client.connected()) {
- client.stop();
-
- }
-
-
-
-
-
-
- /********************SERVER STATUS PAGE*********************/
- /*
- * With this, you can logon to the Sensor from your LAN to find
- * out just what device this IP address is, in case you happen to
- * forget. We can also pull the temperature from this page, and
- * populate it to the camera feed, via ZMTrigger, from a server
- * side wget.
- */
-
-
- //Serve Status Page
- // listen for incoming clients
- EthernetClient client = server2.available();
- if (client) {
- Serial.println(F("web visitor"));
- // an http request ends with a blank line
- boolean currentLineIsBlank = true;
- while (client.connected()) {
- if (client.available()) {
- char c = client.read();
- Serial.write(c);
- // if you've gotten to the end of the line (received a newline
- // character) and the line is blank, the http request has ended,
- // so you can send a reply
- if (c == '\n' && currentLineIsBlank) {
- // send a standard http response header
- client.println("HTTP/1.1 200 OK");
- client.println("Content-Type: text/html");
- //client.println("Connection: close"); // the connection will be closed after completion of the response
- //client.println("Refresh: 5"); // refresh the page automatically every 5 sec
- client.println();
- client.println("<!DOCTYPE HTML>");
- client.println("<html><pre>");
- client.println("<b>Steak Electronics</b>");
- client.println("\"Steak it easy... That is, don't overcook steak\"");
- client.println("");
- //client.println("<b>IP Address:</b>");
- //client.println(Ethernet.localIP());
- client.print("Sensor Location:");
- client.println(LOCATIONOFSENSOR);
- client.print("Type::");
- client.println("HFS-DC06H");
- client.print("Monitor: ");
- client.println(monnum);
- client.print("Temp:");
- client.println(TEMPERATUREVALUE2);
- client.println("</pre></html>");
- break;
- }
- if (c == '\n') {
- // you're starting a new line
- currentLineIsBlank = true;
- } else if (c != '\r') {
- // you've gotten a character on the current line
- currentLineIsBlank = false;
- }
- }
- }
- // give the web browser time to receive the data
- delay(1);
- // close the connection:
- client.stop();
- Serial.println(F("client disconnected"));
- }
-
-
-
-
-
- //write to eeprom if connection failed, and try again upon reboot
- //EEPROM.write(EEPROM_RETRY, switch_pressed);
-
-
-
-
-
-
- } //end main loop
|