I wired up and controlled my garage (two main doors controlling and one side door sensor only) with the following customizable source code running on an Arduino and the SmartThings platform (via a Z Wave shield. (The .groovy file you load on the web, and the .ino file you compile for the Arduino)
These are the materials I used:
$35 Smarthings Arduino Z Wave shield
$25 Arduino Uno
$10 Power supply for Arduino
$10 Wire
$20 Magnetic switches
$8 Relay
It was pretty easy, I developed all the source and did the installation in a single day (tweaked it a little the rest of the weekend) and it has been running stable for about 2 years now.
The garage doors are toggles that I wired into my garage controller button wires, and they only show if the garage doors are ajar. (It does not indicate whether they are closing or opening... that was troublesome to detect with just a magnetic switch and the way garage doors open and close.)
No express or implied warranty are attached to this guide... your milage may vary, etc.
Here is how it looks on my SmartThings (Android) app:
ArduinoGarage.groovy
/**
* Arduino Garage
*
* Author: Marius Piedallu van Wyk
* Date: 2016-08-17
*/
metadata {
// Automatically generated. Make future change here.
definition (name: "Arduino Garage", namespace: "Lailoken", author: "Marius Piedallu van Wyk") {
capability "Switch"
// capability "Sensor"
capability "Contact Sensor"
attribute "contact", "string" // A virtual contact to indicate if anything is open
attribute "leftDoor", "string" // left door open
attribute "rightDoor", "string" // right door open
attribute "backDoor", "string" // side walk-in door open
command "pushLeft" // toggle left
command "pushRight" // toggle right
}
simulator {
}
// Preferences
// tile definitions
tiles {
standardTile("contact", "device.contact", width: 1, height: 1, canChangeIcon: true, canChangeBackground: true) {
state "closed", label: "Closed", icon: "st.doors.garage.garage-closed", backgroundColor: "#79b821"
state "open", label: "Open", icon: "st.doors.garage.garage-open", backgroundColor: "#ffa81e"
}
standardTile("leftDoor", "device.leftDoor", width: 1, height: 1, canChangeIcon: true, canChangeBackground: true) {
state "closed", label: "Closed", icon: "st.doors.garage.garage-closed", backgroundColor: "#79b821", action: "pushLeft", nextState: "open"
state "open", label: "Open", icon: "st.doors.garage.garage-open", backgroundColor: "#ffa81e", action: "pushLeft", nextState: "toggle"
state "toggle", label: "Toggle", icon: "st.doors.garage.garage-opening", backgroundColor: "#89C2E8", action: "pushLeft", nextState: "toggle"
}
standardTile("rightDoor", "device.rightDoor", width: 1, height: 1, canChangeIcon: true, canChangeBackground: true) {
state "closed", label: "Closed", icon: "st.doors.garage.garage-closed", backgroundColor: "#79b821", action: "pushRight", nextState: "open"
state "open", label: "Open", icon: "st.doors.garage.garage-open", backgroundColor: "#ffa81e", action: "pushRight", nextState: "toggle"
state "toggle", label: "Toggle", icon: "st.doors.garage.garage-opening", backgroundColor: "#89C2E8", action: "pushRight", nextState: "toggle"
}
standardTile("backDoor", "device.backDoor", width: 1, height: 1, canChangeIcon: true, canChangeBackground: true) {
state "closed", label: "Closed", icon: "st.contact.contact.closed", backgroundColor: "#79b821"
state "open", label: "Open", icon: "st.contact.contact.open", backgroundColor: "#ffa81e"
}
main(["contact"])
details(["leftDoor", "rightDoor", "backDoor"])
}
preferences {
}
}
def parse(String description) {
def msg = zigbee.parse(description)?.text
log.debug "Parse got '${msg}'"
def parts = msg.split(" ")
def name = parts.length>0?parts[0].trim():null
def value = parts.length>1?parts[1].trim():null
name = value != "ping" ? name : null
def result
if(name == "anyDoor") {
// Use anyDoor as the virtual contact sensor for whole space:
result = createEvent(name: "contact", value: value)
} else {
result = createEvent(name: name, value: value)
}
log.debug result
return result
}
def pushLeft() {
log.debug "Left Button pressed"
zigbee.smartShield(text: "pushLeft").format()
}
def pushRight() {
log.debug "Right Button pressed"
zigbee.smartShield(text: "pushRight").format()
}
arduino-garage.ino
/*****************************************************************************
* Arduino Garage
*
* Author: Marius Piedallu van Wyk
* Date: 2014-07-27
*/
//*****************************************************************************
#include
#include
#define DO_BACK_DOOR
//*****************************************************************************
// Pin Definitions
//*****************************************************************************
#define PIN_LED 13
#define PIN_THING_RX 3
#define PIN_THING_TX 2
#define PIN_BACK_DOOR_CONTACT 4 // input
#define PIN_RIGHT 6 // out
#define PIN_RIGHT_CONTACT 7 // input
#define PIN_LEFT_CONTACT 8 // input
#define PIN_LEFT 9 // out
#define OPEN 0 // HIGH
#define CLOSED 1 // LOW
#define UNKNOWN 2 // --- reset / force update
#define PUSH_DELAY 1200 // milliseconds to keep the button "pushed"
//*****************************************************************************
// Global Variables
//*****************************************************************************
SmartThingsCallout_t messageCallout; // call out function forward decalaration
SmartThings smartthing(PIN_THING_RX, PIN_THING_TX, messageCallout); // constructor
int leftClosed = UNKNOWN;
int rightClosed = UNKNOWN;
int backClosed = UNKNOWN;
int anyOpen = UNKNOWN;
bool isDebugEnabled=false; // enable or disable debug in this example
int stateLED; // state to track last set value of LED
int stateNetwork; // state of the network
//*****************************************************************************
// Local Functions
//*****************************************************************************
//*****************************************************************************
void pushLeft()
{
smartthing.shieldSetLED(0, 0, 2); // blue
digitalWrite(PIN_LEFT,LOW);
delay(PUSH_DELAY);
digitalWrite(PIN_LEFT,HIGH);
smartthing.shieldSetLED(0, 0, 0); // off
}
//*****************************************************************************
void pushRight()
{
smartthing.shieldSetLED(0, 2, 0); // green
digitalWrite(PIN_RIGHT,LOW);
delay(PUSH_DELAY);
digitalWrite(PIN_RIGHT,HIGH);
smartthing.shieldSetLED(0, 0, 0); // off
}
//*****************************************************************************
int isClosed(int pin)
{
// LOW -> closed
// HIGH -> open
return (digitalRead(pin) == LOW)?CLOSED:OPEN;
}
//*****************************************************************************
void updateDoorState()
{
int newState;
String msg;
newState = isClosed(PIN_LEFT_CONTACT);
if (leftClosed != newState)
{
leftClosed = newState;
if(leftClosed == CLOSED) msg = "leftDoor closed";
else msg = "leftDoor open";
smartthing.send(msg);
if(isDebugEnabled) Serial.println(msg);
return; // only one message per loop
}
newState = isClosed(PIN_RIGHT_CONTACT);
if (rightClosed != newState)
{
rightClosed = newState;
if(rightClosed == CLOSED) msg = "rightDoor closed";
else msg = "rightDoor open";
smartthing.send(msg);
if(isDebugEnabled) Serial.println(msg);
return; // only one message per loop
}
#ifdef DO_BACK_DOOR
newState = isClosed(PIN_BACK_DOOR_CONTACT);
if (backClosed != newState)
{
backClosed = newState;
if(backClosed == CLOSED) msg = "backDoor closed";
else msg = "backDoor open";
smartthing.send(msg);
if(isDebugEnabled) Serial.println(msg);
return; // only one message per loop
}
#endif
newState = CLOSED;
#ifdef DO_BACK_DOOR
if(rightClosed == OPEN || leftClosed == OPEN || backClosed == OPEN) newState = OPEN;
#else
if(rightClosed == OPEN || leftClosed == OPEN) newState = OPEN;
#endif
if(anyOpen != newState)
{
anyOpen = newState;
if(anyOpen == CLOSED) msg = "anyDoor closed";
else msg = "anyDoor open";
smartthing.send(msg);
if(isDebugEnabled) Serial.println(msg);
return; // only one message per loop
}
}
//*****************************************************************************
void setNetworkStateLED()
{
SmartThingsNetworkState_t tempState = smartthing.shieldGetLastNetworkState();
if (tempState != stateNetwork)
{
switch (tempState)
{
case STATE_NO_NETWORK:
if (isDebugEnabled) Serial.println("NO_NETWORK");
smartthing.shieldSetLED(2, 2, 0); // red
break;
case STATE_JOINING:
if (isDebugEnabled) Serial.println("JOINING");
smartthing.shieldSetLED(2, 2, 0); // yellow
break;
case STATE_JOINED:
if (isDebugEnabled) Serial.println("JOINED");
smartthing.shieldSetLED(0, 0, 0); // off
// force report of current door state
leftClosed = UNKNOWN;
rightClosed = UNKNOWN;
backClosed = UNKNOWN;
anyOpen = UNKNOWN;
break;
case STATE_JOINED_NOPARENT:
if (isDebugEnabled) Serial.println("JOINED_NOPARENT");
smartthing.shieldSetLED(2, 0, 2); // purple
break;
case STATE_LEAVING:
if (isDebugEnabled) Serial.println("LEAVING");
smartthing.shieldSetLED(2, 2, 0); // yellow
break;
default:
case STATE_UNKNOWN:
if (isDebugEnabled) Serial.println("UNKNOWN");
smartthing.shieldSetLED(2, 0, 0); // red
break;
}
stateNetwork = tempState;
}
}
//*****************************************************************************
void setup()
{
// setup default state of global variables
isDebugEnabled = true;
stateLED = 0; // matches state of hardware pin set below
stateNetwork = STATE_JOINED; // set to joined to keep state off if off
// setup hardware pins
pinMode(PIN_LED, OUTPUT); // define PIN_LED as an output
pinMode(PIN_RIGHT, OUTPUT);
pinMode(PIN_LEFT, OUTPUT);
digitalWrite(PIN_RIGHT, HIGH);
digitalWrite(PIN_LEFT, HIGH);
digitalWrite(PIN_LED, LOW); // set value to LOW (off) to match stateLED=0
pinMode(PIN_LEFT_CONTACT, INPUT_PULLUP);
pinMode(PIN_RIGHT_CONTACT, INPUT_PULLUP);
pinMode(PIN_BACK_DOOR_CONTACT, INPUT_PULLUP);
if(isDebugEnabled)
{ // setup debug serial port
Serial.begin(9600); // setup serial with a baud rate of 9600
Serial.println("setup.."); // print out 'setup..' on start
}
}
//*****************************************************************************
void loop()
{
// run smartthing logic
smartthing.run();
// Check network connections (and send initial states on Join)
setNetworkStateLED();
if(stateNetwork == STATE_JOINED)
{
// Check the open/closed state of the doors
updateDoorState();
}
}
//*****************************************************************************
void messageCallout(String message)
{
smartthing.shieldSetLED(2, 2, 2); // white
// if debug is enabled print out the received message
if(isDebugEnabled)
{
Serial.print("Received message: '");
Serial.print(message);
Serial.println("'");
}
if(message.equals("pushLeft"))
{
pushLeft();
}
else if(message.equals("pushRight"))
{
pushRight();
}
smartthing.shieldSetLED(0, 0, 0); // off
}
Comments