DSC Alarm Arduino Digispark ATTINY85 With WRT54G Router
by wrt54gfanatic in Circuits > Arduino
1318 Views, 2 Favorites, 0 Comments
DSC Alarm Arduino Digispark ATTINY85 With WRT54G Router
The Idea is to use a Digispark and WRT54G router to connect to a DSC security alarm, and send email alerts when an alarm is triggered. Although the Digispark expects 5V, a WRT54G 3.3V line can easily supply the 10mA required. The 12V Keybus signal is fed through 10K resistors to pins 1,2, please share any better optocoupler style solutions.
I am using a PC1555MX, and believe DSC Security Alarms of that time should work.
On the Alarm side, the phone home features should be disabled:
*8 5555 015 7 ##
*8 5555 371 9999 ##
*8 5555 380 1 ##
I did a factory reset, and had to reprogram all the zones as Instant, Delayed, and Smoke.
It was also necessary to disable the End of the Line Resistors using:
*8 5555 013 1 ##
Try not to do a factory reset, as that will probably takes hours of reading to setup the zones again.
A special DD-WRT Micro Firmware is modified to work on a WRT54G V1, V2, V3 with a shellscript that runs in a loop and runs msmtp to send a email alerts. You don't need any extra memory or SD cards.
The Arduino is constantly reading the yellow and green keybus wires, and outputs active zones, for example:
if Zone 1 & 5 is triggered this will be output followed by a newline:
15
If the system is armed and zone 1&6 are triggered, the Digispark will output this on pin 0:
A16
The shellscript will read the output into a variable:
read i < /dev/tts/0
And depending on what the delay timeout is, will send an email every time something changes:
msmtp --host=smtp.gmail.com --port=587 --protocol=smtp --auth=on --user=username@gmail.com --passwordeval='echo yourpasswordhere' --tls=on --tls-starttls --tls-certcheck=off --from=username@gmail.com username@gmail.com
By default only zones 1 & 2 react to the armed state, you can change the other zones by pasting the following into that zones if statement:
[ 'A' = $armed ] &&
Here is the shellscript code:
#!/bin/sh #netsh wlan show profiles #netsh wlan show profile name=ProfileName key=clear #please find a better way to store a password!!! i="ALR ZN 3" #ntpclient -l -h pool.ntp.org -c 1 -s echo "" > /tmp/log #clear after time passes zone1='' zone2='' zone3='' zone4='' zone5='' zone6='' while true do a=0 delay=60 #900 #every 15 minutes tic=$(cat /proc/uptime |sed 's/\..*//') elap_time=0 armed="" sendemail="" logoutput="" while [ "$elap_time" -le "$delay" ] do toc=$(cat /proc/uptime |sed 's/\..*//') #echo "$toc" elap_time=$(expr "$toc" - "$tic") #echo "$elap_time" ##read -p "Input : " i #for testing with a shell read i </dev/tts/0 #keep reading lines from serial port armed=$(echo -n "$i"|sed 's/[" "B-Z0-9]//g') i=$(echo "$i"|sed 's/[" "A-Z]//g') #a case statement won't work if more than one alarm exists at time... if [ 'A' = $armed ] && [ '1' = $(echo "$i"|sed 's/[" "A-Z,0,2,3,4,5,6,7,8]//g') ]; then if [ -z "$zone1" ]; then sendemail=1 echo -e 'Alarm 1: Front Door/Side Door<br>' >> /tmp/log zone1='1' fi elif [ -n "$zone1" ]; then echo "reseting zone 1" zone1='' fi if [ 'A' = $armed ] && [ '2' = $(echo "$i"|sed 's/[" "A-Z,0,1,3,4,5,6,7,8]//g') ]; then if [ -z "$zone2" ]; then sendemail=1 echo -e 'Alarm 2: Hall Motion<br>' >> /tmp/log zone2='1' fi elif [ -n "$zone2" ]; then echo "reseting zone 2" zone2='' fi if [ '3' = $(echo "$i"|sed 's/[" "A-Z,0,1,2,4,5,6,7,8]//g') ]; then #paste armed here if you want if [ -z "$zone3" ]; then sendemail=1 echo -e 'Alarm 3: Main Floor Smoke<br>' >> /tmp/log zone3='1' fi elif [ -n "$zone3" ]; then echo "reseting zone 3" zone3='' fi if [ '4' = $(echo "$i"|sed 's/[" "A-Z,0,1,2,3,5,6,7,8]//g') ]; then if [ -z "$zone4" ]; then sendemail=1 echo -e 'Alarm 4: Basement Smoke<br>' >> /tmp/log zone4='1' fi elif [ -n "$zone4" ]; then echo "reseting zone 4" zone4='' fi if [ '5' = $(echo "$i"|sed 's/[" "A-Z,0,1,2,3,4,6,7,8]//g') ]; then if [ -z "$zone5" ]; then sendemail=1 echo -e 'Alarm 5: High Water<br>' >> /tmp/log zone5='1' fi elif [ -n "$zone5" ]; then echo "reseting zone 5" zone5='' fi if [ '6' = $(echo -n "$i"|sed 's/[" "A-Z,0,1,2,3,4,5,7,8]//g') ]; then if [ -z "$zone6" ]; then sendemail=1 echo -e 'Alarm 6: Basement Low Temp<br>' >> /tmp/log zone6='1' fi elif [ -n "$zone6" ]; then echo "reseting zone 6" zone6='' fi done echo "email section" if [ -z "$sendemail" ]; then echo nothing else #email i=$( sed '1!G;h;$!d' /tmp/log | head -n1| sed 's/:.*//' ) { echo To: username@gmail.com echo Subject: $i echo From: username@gmail.com echo 'Content-Type: text/html; charset=\"utf8\"' echo '' echo '' sed '1!G;h;$!d' /tmp/log && echo "<br>" && echo `date` echo '' echo '' } |msmtp --host=smtp.gmail.com --port=587 --protocol=smtp --auth=on --user=username@gmail.com --passwordeval='echo yourpasswordhere' --tls=on --tls-starttls --tls-certcheck=off --from=username@gmail.com username@gmail.com sendemail="" echo "" > /tmp/log #clear after sending logoutput="" fi done
Supplies
Router Setup Instructions
load the attached firmware onto your WRT54G V1, V2, V3 (4mb) series router using a network cable on any of the 4 switching ports. This is done by setting your computer IP address to 192.168.1.2, opening TFTP, setting the tftp address to 192.168.1.1, browse for the dd-wrt.v24-18946_NEWD_micro-plus_ssh_serial_openSSL_smtp.bin file. The key is to plug in the power into the WRT54G, then press Upgrade just as the green light starts flickering. It takes several attempts to get this. The DD-WRT guides might offer better help.
Use AP Client mode or wired, ensure the WRT54G is on a different subnet from the main router:
if your home router is on 192.168.0.1, set your WRT54G to 192.168.1.1
paste these as shown in the screenshots:
ntpclient -l -h pool.ntp.org -c
nvram get rc_custom >/tmp/alarmconnect
sh /tmp/alarmconnect
put """" into rc_custom as shown and paste x.sh in between the quotes replace all username@gmail.com yourpasswordhere and with your email details. This assumes your router is in your home, and not in a public environment, storing passwords in plaintext is bad, if anyone can implement a better way I'll use it.
Setup Your Arduino Digispark
Set to 8mhz no USB
Include the attiny85ser BasicSerial Library
Compile and upload DSC_READ4_simplified:
#include <br>#define CLK 2 // Keybus Yellow #define DTA 1 // Keybus Green
char hex[] = "0123456789abcdef"; String st, old; unsigned long lastData; void setup() { pinMode(CLK,INPUT); pinMode(DTA,INPUT); serOut("Ready!"); // Interrupt attachInterrupt(0,clkCalled,RISING); } void loop() { char buf[10]; if (waitCLKchange(1) < 2000) return; String stc = st; st = ""; int cmd = getBinaryData(stc,0,8); if (stc == old) return; if (cmd == 0) return; old = stc; if (cmd == 0x05) { //getBinaryData(stc,12,1); //do nothing on error //getBinaryData(stc,13,1); //do nothing on bypass //getBinaryData(stc,14,1); //do nothing on Memory if (getBinaryData(stc,15,1)) TxByte(65); //send letter A for Armed //getBinaryData(stc,16,1); //do nothing on ready return; } if (cmd == 0x27) { int zones = getBinaryData(stc,8+1+8+8+8+8,8); if (zones & 1) TxByte(49); //send #1 for zone 1... if (zones & 2) TxByte(50); if (zones & 4) TxByte(51); if (zones & 8) TxByte(52); if (zones & 16) TxByte(53); if (zones & 32) TxByte(54); if (zones & 64) TxByte(55); if (zones & 128) TxByte(56); TxByte(10); //send new line to send last event return; }
} void serOut(const char* str) { while (*str) TxByte (*str++); } void clkCalled() { if (st.length() > 200) return; // Do not overflow the arduino's little ram if (digitalRead(DTA)) st += "1"; else st += "0"; } unsigned long waitCLKchange(int currentState) { unsigned long c = 0; while (digitalRead(CLK) == currentState) { delayMicroseconds(10); c += 10; if (c > 10000) break; } return c; } unsigned int getBinaryData(String &st, int offset, int length) { int buf = 0; for(int j=0;j