DSC Alarm Arduino Digispark ATTINY85 With WRT54G Router
by wrt54gfanatic in Circuits > Arduino
1442 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
doneSupplies
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