DSC Alarm Arduino Digispark ATTINY85 With WRT54G Router

by wrt54gfanatic in Circuits > Arduino

1264 Views, 2 Favorites, 0 Comments

DSC Alarm Arduino Digispark ATTINY85 With WRT54G Router

dsc_connection.png

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

administration_commands_rc_custom.png
DDWRT-00.png
DDWRT-01.png
DDWRT-02.png
DDWRT-03.png
DDWRT-04.png
DDWRT-05.png

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

Digispark Info 01.png
Digispark Info 02.png

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