Using a Sick WS15-D1130 Infrared Diode pair to act as a hardware motion detection sensor for Zoneminder. Also testing out an Omrom photo electric sensor, the E3F2-R2C4. This is a tripwire alarm sensor. When the beam is blocked, the alarm is activated.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

421 lines
10 KiB

/*
*
* 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, 0x15 };
//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. DO NOT USE
//String username="username";
//String password="password";
EthernetClient client;
#define ZMTRIGGERPORT 6802
//set to 1 if using sick sensor (on analog pin)
#define SICK 0
/***************Pins***************/
#define SPEAKER_PIN 6
#define LED_PIN 9
//#define RESETPIN 2 //may not be needed here
#define SENSORPIN A1
#define TEMPPIN A0
/***************Variables************/
int MotionSensorRead = 0;
uint8_t AlarmActive = 0;
char* ZMTriggerMessage = "1234567890123456789012345678901234"; //Initialize this with dummy data
int TEMPERATUREVALUE = 0;
int TEMPERATUREVALUE2 = 0;
// 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
// Initialize the Ethernet server library
#define LISTENPORT 80// (port 80 is default for HTTP):
EthernetServer server2 = EthernetServer(LISTENPORT);
//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);
//Be careful. Areg is 1.1v!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
analogReference(INTERNAL);
Ethernet.begin(mac, ip);
server2.begin();
Serial.print("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 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));
delay(10);
TEMPERATUREVALUE = analogRead(TEMPPIN);
Serial.print("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(10);
if(DEBUGMODE){
delay(10);
}
//Motion sensing for Sick Photoelectric sensor only
//upon boot, values are around 400 sometimes, so only alert at higher
if(SICK == 1){
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);
}
}
}//end sick
//disconnect
if (!client.connected()) {
client.stop();
}
//Serve Status Page
// listen for incoming clients
EthernetClient client = server2.available();
if (client) {
Serial.println("new client");
// 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.println("<b>Sensor Location:</b>");
client.println("Bay Four - Tool Room");
client.println("<b>Type of Sensor</b>:");
client.println("Microwave - HFS-DC06H");
client.println("<b>Temperature Sensor Value:</b>");
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("client disconnected");
}
//write to eeprom if connection failed, and try again upon reboot
//EEPROM.write(EEPROM_RETRY, switch_pressed);
} //end main loop