Skip to content

Instantly share code, notes, and snippets.

@lyons189
Last active November 2, 2016 19:06
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save lyons189/e5b30109fdaec805d474 to your computer and use it in GitHub Desktop.
Save lyons189/e5b30109fdaec805d474 to your computer and use it in GitHub Desktop.
These 3 files are used to get ADT integration working
/**
* ADT Device Handler
*
* Copyright 2014 craig Lyons
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
*/
// Automatically generated. Make future change here.
definition(
name: "ADT Device Handler",
namespace: "",
author: "craig Lyons",
description: "Handles my fake devices based off of ADT",
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience%402x.png"
)
preferences {
section("Which Shield are you using") {
input "shield", "capability.alarm", title: "Which Shield?"
}
section("Front Door"){
input "zone2", "capability.contactSensor", title: "Which Door?"
}
section("Back Door"){
input "zone5", "capability.contactSensor", title: "Which Door?"
}
section("Garage Door"){
input "zone3", "capability.contactSensor", title: "Which Door?"
}
section("Basement Door"){
input "zone6", "capability.contactSensor", title: "Which Door?"
}
section("Hall Motion"){
input "zone4", "capability.motionSensor", title: "Which Motion?"
}
section("Number of Seconds motion stays active") {
input "motionDelay", "number", description: "Number of seconds", required: true
}
}
def installed() {
log.debug "Installed with settings: ${settings}"
initialize()
}
def updated() {
log.debug "Updated with settings: ${settings}"
unsubscribe()
initialize()
}
def initialize() {
// TODO: subscribe to attributes, devices, locations, etc.
subscribe(shield, "hallMotion", hallMotion)
subscribe(shield, "frontDoor", frontDoor)
subscribe(shield, "backDoor", backDoor)
subscribe(shield, "garageDoor", garageDoor)
subscribe(shield, "basementDoor", basementDoor)
}
def hallMotion(evt) {
//log.debug "${shield.label ?: shield.name} has motion"
//log.debug shield.latestValue("hallMotion")
//log.debug zone4.latestValue("motionSensor")
if (evt.value == "Active") {
//log.info "Motion Active"
zone4.Active()
}
else if (evt.value == "inActive") {
//log.info "delay ${motionDelay}"
//zone4.semiActive()
runIn ( motionDelay, motionInActive, overwrite: true) // Schedule to change motion state
}
}
def motionInActive()
{
//log.info "Function inActive";
zone4.inActive()
}
def frontDoor(evt) {
log.debug "${shield.label ?: shield.name} is open"
log.debug shield.latestValue("frontDoor")
log.debug zone2.latestValue("contact")
if (evt.value == "open") {
log.info "frontDoor open"
zone2.open()
} else if (evt.value == "closed") {
log.info "frontDoor closed"
zone2.close()
}
}
def backDoor(evt) {
log.debug "${shield.label ?: shield.name} is open"
log.debug shield.latestValue("backDoor")
log.debug zone2.latestValue("backDoor")
if (evt.value == "open") {
log.info "backDoor open"
zone5.open()
} else if (evt.value == "closed") {
log.info "backDoor closed"
zone5.close()
}
}
def garageDoor(evt) {
log.debug "${shield.label ?: shield.name} is open"
log.debug shield.latestValue("garageDoor")
log.debug zone2.latestValue("garageDoor")
if (evt.value == "open") {
log.info "garageDoor open"
zone3.open()
} else if (evt.value == "closed") {
log.info "garageDoor closed"
zone3.close()
}
}
def basementDoor(evt) {
log.debug "${shield.label ?: shield.name} is open"
log.debug shield.latestValue("basementDoor")
log.debug zone2.latestValue("basementDoor")
if (evt.value == "open") {
log.info "basementDoor open"
zone6.open()
} else if (evt.value == "closed") {
log.info "basementDoor closed"
zone6.close()
}
}
#include <SmartThingsMega.h> //special library for Arduino Mega card
#include <Timer.h>
// PASSCODE = your personal code. It's hard coded here so you don't need to post it within Smartthings app.
String PASSCODE = "####";
#define PIN_THING_LED 13
#define BUFFER_SIZE 300 // max message length from ADT
#define ARDUINO_CHECK_IN 30000
#define UPDATE_PERIOD_ARM 25283
#define UPDATE_PERIOD_ALARM 30123
#define UPDATE_PERIOD_ZONE 50234
SmartThingsCallout_t messageCallout; // call out function forward decalaration
SmartThingsMega smartthing(&Serial2, messageCallout); // constructor
Timer timer;
char buffer[BUFFER_SIZE];
boolean DEBUG = false;
boolean LIVE = false;
int bufferIdx;
void setup()
{
pinMode(PIN_THING_LED, OUTPUT); // define PIN_LED as an output
Serial1.begin(115200); // intialize ADT serial stream
Serial.begin(115200); // intialize DEBUG or LIVE serial stream
bufferIdx = 0;
//timer.every(ARDUINO_CHECK_IN, checkIn);
//timer.every(UPDATE_PERIOD_ARM, sendArmStatus);
//timer.every(UPDATE_PERIOD_ALARM, sendAlarmStatus);
//timer.every(UPDATE_PERIOD_ZONE, sendZoneStatus);
digitalWrite(PIN_THING_LED, HIGH); // Turn Smartthings LED on.
smartthing.shieldSetLED(0, 1, 0); // Turn LED "green" to show startup
delay(250);
if (DEBUG || LIVE)
{
if (DEBUG)
{
smartthing.shieldSetLED(1, 0, 0); // Turn LED "Red" for DEBUG mode
delay(250);
}
if (LIVE)
{
smartthing.shieldSetLED(0, 0, 1); // Turn LED "Blue" for LIVE mode
delay(250);
}
Serial.println("Ready");
}
smartthing.shieldSetLED(0, 0, 0);
digitalWrite(PIN_THING_LED, LOW); // Turn of LED
}
void loop()
{
char data, arduino_input;
timer.update(); // update periodic events
smartthing.run(); // run smartthing logic
if (DEBUG || LIVE)
{
if (Serial.available() > 0)
{
arduino_input = Serial.read();
String command = "X";
command.setCharAt(0,arduino_input);
Serial1.print(command);
if(DEBUG)
{
Serial.print("type Code: <");
Serial.print(arduino_input);
Serial.println(">");
Serial.println(command);
delay (250);
smartthing.send(command);
}
}
}
if (Serial1.available() > 0)
{
data = Serial1.read();
if (DEBUG || LIVE)
{
Serial.print(data);
}
if (data == '\r' && bufferIdx > 0)
{
// if line is completed, review command
buffer[bufferIdx] = '\0';
bufferIdx = 0;
String str(buffer);
int quoteIndex = str.indexOf('"');
String cmd = str.substring(quoteIndex, str.length());
if(cmd.length() > 0)
{
smartthing.send(cmd);
}
else if (str.equals("!Sending.done") || str.indexOf("!RFX:") >=0)
{
}
else
{
smartthing.send(str);
}
if (DEBUG)
{
Serial.println("");
Serial.print("str Code: <");
Serial.println(str);
}
if (LIVE)
{
Serial.println("");
Serial.print("cmd Code: ");
Serial.println(cmd);
}
}
// otherwise append to buffer (ignore \n)
else if (data != '\n')
{
buffer[bufferIdx] = data;
bufferIdx++;
if (bufferIdx >= BUFFER_SIZE)
{
smartthing.send("ER:Buffer overrun");
bufferIdx = 0;
}
}
}
}
void debug()
{
DEBUG = true;
smartthing.send("MODE: Debug");
digitalWrite(PIN_THING_LED, HIGH); // turn LED on
smartthing.shieldSetLED(1, 0, 0); // turn LED Red for DEBUG
delay(250);
smartthing.shieldSetLED(0, 0, 0);
digitalWrite(PIN_THING_LED, LOW); // turn LED off
}
void Live()
{
LIVE = true;
smartthing.send("MODE: Live");
digitalWrite(PIN_THING_LED, HIGH); // turn LED on
smartthing.shieldSetLED(0, 0, 1); // turn LED Blue for LIVE
delay(250);
smartthing.shieldSetLED(0, 0, 0);
digitalWrite(PIN_THING_LED, LOW); // turn LED off
}
void noDebug()
{
DEBUG = false;
LIVE = false;
smartthing.send("MODE: noDebug");
digitalWrite(PIN_THING_LED, HIGH); // turn LED on
smartthing.shieldSetLED(0, 1, 0); // turn LED Green for no DEBUG or LIVE
delay(250);
smartthing.shieldSetLED(0, 0, 0);
digitalWrite(PIN_THING_LED, LOW); // turn LED off
}
void checkIn ()
{
smartthing.send("ADT Check-in");
}
void messageCallout(String message)
{
String code = message.substring(0,6);
String cmd = message.substring(6);
if(message.length()>0)
{
String code = message.substring(0,6);
Serial.print("Smart-things sent: <");
Serial.print(message);
Serial.println(">");
if (DEBUG || LIVE)
{
Serial.print("Smart-things sent: <");
Serial.print(message);
Serial.println(">");
delay(250);
smartthing.send(message);
}
if (message.equals("MODE: debug"))
{
debug();
}
else if (message.equals("MODE: Live"))
{
Live();
}
else if (message.equals("MODE: both"))
{
debug();
Live();
}
else if (message.equals("MODE: noDebug"))
{
noDebug();
}
else if(code.equals("[CODE]"))
{
Serial1.println(PASSCODE + cmd);
if(DEBUG || LIVE)
{
Serial.print(PASSCODE);
Serial.print("+");
Serial.println(cmd);
Serial.print("Sent Alarm: ");
Serial.println(PASSCODE + cmd);
delay(250);
smartthing.send(PASSCODE + cmd);
}
}
}
}
//
// In device configuration select the following capabilities: switch, contact and alarm
//
metadata {
// Automatically generated. Make future change here.
definition (name: "ADT", author: "craig Lyons") {
capability "Alarm"
capability "Contact Sensor"
capability "Switch"
capability "Motion Sensor"
attribute "backDoor", "string"
attribute "frontDoor", "string"
attribute "garageDoor", "string"
attribute "basementDoor", "string"
attribute "hallMotion", "string"
attribute "debug", "string"
attribute "chime", "string"
attribute "secs", "string"
attribute "msg", "string"
command "disarm"
command "armStay"
command "armAway"
command "noDebug"
command "live"
command "debug"
command "both"
command "chime"
command "status"
}
// Simulator metadata
simulator {
}
// UI tile definitions
tiles {
standardTile("alarm", "device.alarm", width: 1, height: 1) {
state "Disarmed", label:'${name}', action:"armStay", icon:"st.Home.home2", backgroundColor:"#ffffff"
state "Away", label:'${name}', action:"disarm", icon:"st.Home.home3", backgroundColor:"#79b821"
state "Stay", label:'${name}', action:"disarm", icon:"st.Home.home4", backgroundColor:"#79b821"
state "aWarning", label:'Warning', action:"disarm", icon:"st.Home.home3", backgroundColor:"#FF3333"
state "sWarning", label:'Warning', action:"disarm", icon:"st.Home.home4", backgroundColor:"#FF3333"
state "armingAway", label:'Away', action:"disarm", icon:"st.Home.home3", backgroundColor:"#ffa81e"
state "armingStay", label:'Stay', action:"disarm", icon:"st.Home.home4", backgroundColor:"#ffa81e"
}
standardTile("Stay", "device.alarm", width: 1, height: 1, decoration: "flat"){
state "Stay", label:'${name}', action: "armStay", icon:"st.Home.home4", nextState: "Pressed"
state "Pressed", label:'Armed', action: "armStay", icon:"st.Home.home4"
}
standardTile("Away", "device.alarm", width: 1, height: 1, decoration: "flat"){
state "Away", label:'${name}', action: "armAway", icon:"st.Home.home3", nextState: "Pressed"
state "Pressed", label:'Armed', action: "armStay", icon:"st.Home.home3"
}
standardTile("backDoor", "device.backDoor", width: 1, height:1) {
state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#ffa81e"
state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#79b821"
}
standardTile("frontDoor", "device.frontDoor", width: 1, height:1) {
state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#ffa81e"
state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#79b821"
}
standardTile("garageDoor", "device.garageDoor", width: 1, height:1) {
state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#ffa81e"
state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#79b821"
}
standardTile("basementDoor", "device.basementDoor", width: 1, height:1) {
state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#ffa81e"
state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#79b821"
}
standardTile("hallMotion", "device.hallMotion", width: 1, height:1) {
state "inActive", label: 'No Motion', icon: "st.motion.motion.inactive", backgroundColor: "#ffffff"
state "Active", label: 'Motion', icon: "st.motion.motion.active", backgroundColor: "#53a7c0"
}
standardTile("chime", "chime", width: 1, height: 1, inactiveLabel: false, decoration: "flat"){
state "on", label: 'Chime On', action: "chime", icon: "st.custom.sonos.unmuted", backgroundColor: "#ffffff", nextState: "unk"
state "off", label: 'Chime Off', action: "chime", icon: "st.custom.sonos.muted", backgroundColor: "#ffffff", nextState: "unk"
state "unk", label: 'Changing', icon: "st.custom.sonos.unmuted", backgroundColor: "#ffffff"
}
standardTile("debug", "debug", width: 1, height: 1){
state "none", label: '', action: "live", icon: "st.secondary.configure", backgroundColor: "#ffffff"
state "live", label: '', action: "debug", icon: "st.secondary.test", backgroundColor: "#53a7c0", nextState: "debug"
state "debug", label: '', action: "noDebug", icon: "st.secondary.test", backgroundColor: "#FF3333"
}
standardTile("Disarm", "device.alarm", width: 1, height: 1, decoration: "flat"){
state "da", label:'Disarm', action: "disarm", icon:"st.Home.home2"
}
valueTile("secs", "device.secs") {
state "default", label:'${currentValue}'
}
valueTile("msg", "device.msg", width: 3, height:1, inactiveLabel: false, decoration: "flat") {
state "default", label:'${currentValue}'
}
main(["alarm"])
details(["alarm","Stay","Away","frontDoor","garageDoor","chime","backDoor","basementDoor","Disarm","hallMotion","debug","secs",
"msg"])
}
}
// Parse incoming device messages to generate events
def parse(String description) {
def result = []
//log.info "Parsing: < ${description} >"
def msg = zigbee.parse(description)?.text
log.debug "Raw MSG : < ${msg} >"
if (msg.contains("ping")) {}
else {result << createEvent(name: "msg", value: msg)}
if (msg.contains("Hit") && msg.contains(" for faults"))
{
status()
}
if (msg.contains("DISARMED"))
{
result << createEvent(name: "alarm", value: "Disarmed")
result << createEvent(name: "Away", value: "Away")
result << createEvent(name: "Stay", value: "Stay")
result << createEvent(name: "secs", value: "-")
if (msg.contains("CHIME"))
{
result << createEvent(name: "chime", value: "on")
}
else
{
result << createEvent(name: "chime", value: "off")
}
}
if (msg.contains("DISARM SYSTEM"))
{
if (device.currentValue("alarm").contains("Away"))
{
result << createEvent(name: "alarm", value: "sWarning")
}
else if (device.currentValue("alarm").contains("Stay"))
{
result << createEvent(name: "alarm", value: "aWarning")
}
else
{
result << createEvent(name: "alarm", value: "sWarning")
}
result << createEvent(name: "alarm", value: "Warning")
}
if (msg.contains("Ready to Arm"))
{
result << createEvent(name: "hallMotion", value: "inActive")
result << createEvent(name: "frontDoor", value: "closed")
result << createEvent(name: "garageDoor", value: "closed")
result << createEvent(name: "basementDoor", value: "closed")
result << createEvent(name: "backDoor", value: "closed")
}
if (msg.contains("ARMED"))
{
if (msg.contains("STAY"))
{
if (msg.contains("May Exit Now"))
{
result << createEvent(name: "alarm", value: "armingStay")
result << createEvent(name: "secs", value: msg.substring(msg.length()-3,msg.length()-1))
}
else
{
result << createEvent(name: "alarm", value: "Stay")
result << createEvent(name: "secs", value: "-")
}
}
else if (msg.contains("AWAY"))
{
if (msg.contains("May Exit Now"))
{
result << createEvent(name: "alarm", value: "armingAway")
result << createEvent(name: "secs", value: msg.substring(msg.length()-3,msg.length()-1))
}
else
{
result << createEvent(name: "alarm", value: "Away")
result << createEvent(name: "secs", value: "-")
}
}
}
if (msg.contains("FAULT"))
{
log.info "fault"
if (msg.contains("01"))
{
log.info "01"
result << createEvent(name: "backDoor", value: "open")
}
else if (msg.contains("02"))
{
log.info "02"
result << createEvent(name: "frontDoor", value: "open")
}
else if (msg.contains("03"))
{
log.info "03"
result << createEvent(name: "garageDoor", value: "open")
}
else if (msg.contains("04"))
{
log.info "04"
result << createEvent(name: "hallMotion", value: "Active")
}
else if (msg.contains("05"))
{
log.info "05"
result << createEvent(name: "backDoor", value: "open")
}
else if (msg.contains("06"))
{
log.info "06"
result << createEvent(name: "basementDoor", value: "open")
}
}
if (msg.contains("MODE"))
{
if (msg.contains("Live"))
{
result << createEvent(name: "debug", value: "live")
}
if (msg.contains("debug"))
{
result << createEvent(name: "debug", value: "debug")
}
if (msg.contains("noDebug"))
{
result << createEvent(name: "debug", value: "none")
}
}
//log.debug "Parse returned ${result?.descriptionText}"
return result
}
// Commands sent to the device
def on() {
log.debug "Trying to arm alarm"
}
def armAway(){
zigbee.smartShield(text: "[CODE]2").format()
}
def disarm() {
zigbee.smartShield(text: "[CODE]1***").format()
}
def armStay() {
zigbee.smartShield(text: "[CODE]3").format()
}
def chime() {
zigbee.smartShield(text: "[CODE]9").format()
}
def debug() {
zigbee.smartShield(text: "Mode: debug").format()
}
def live() {
zigbee.smartShield(text: "MODE: Live").format()
}
def noDebug() {
zigbee.smartShield(text: "MODE: noDebug").format()
}
def status() {
//disarm()
log.trace "here"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment