Arduino SmartShield Garage Controller

I have seen a bunch of threads for folks looking for solutions for controlling garage doors via SmartThings and I just finished mine this weekend, so I thought I would share.

My solution was to use an Arduino Uno with SmartThings Shield, 2-channel relay, and 2 magnetic reed switches. Total cost of all parts was about $85 plus some misc wire to connect everything up. This controls two garage doors and provides feedback as to their state (open/closed).

Here’s the parts list:

  • Arduino Uno
  • Power Adapter (for the Uno)
  • 2-Channel Relay
  • 2x Magnetic Reed Switches
  • SmartThings Arduino Shield
  • Two Caveats: 1) My Uno came in a starter kit I bought a while ago, so the one linked to above is not the exact one I have, but it should work the same. 2) The reed switches here are not the exact ones I bought (I got mine at Fry’s) But they look nearly identical to these.

    Two pins on the Arduino are hooked to the inputs for the relay switches. When that pin goes high, it closes the relay. I then hooked the relay’s normally open connection to the same two inputs on the garage door motor where my manual wall switch hooks in (I left the wall switch still there, so there are now two wires into each of the two connections on the garage door motor). When the Arduino receives the “pushLeft” or “pushRight” command - it closes the left or right relay for 1 sec to simulate someone pushing the physical button for 1 sec. This actuates the garage door.

    Two other pins on the Arduino are used to read the state of the magnetic reed switches. I use the pins on the Arduino in INPUT_PULLUP mode, which means the Arduino holds them high with a pull-up resistor and when the reed switch closes, it gets pulled low (to ground). This simply means when I read the pins in the Arduino code, a HIGH indicates the door is open, and LOW means it’s closed. The “common” side of the reed switch is just hooked to ground on the Arduino board.

    I put the whole thing in a plastic project box and zip-tied it to one of the brackets which mount one of the garage door motors to the ceiling.

    The device controller is pretty simple - it just has two buttons to actuate each of the garage doors. And it looks like this:

    Garage Door Device Controller

    The Device Type Code has two custom attributes: leftDoor and rightDoor, and two custom commands: pushLeft and pushRight. The Code is:

/**
 *  Garage Door
 *
 *  Author: Steve Sell
 *  Date: 2014-02-02
 */

metadata {
	// Preferences
    
	
	// tile definitions
	tiles {
		standardTile("leftDoor", "device.leftDoor", width: 1, height: 1, canChangeIcon: true, canChangeBackground: true) {
			state "closed", label: 'Closed', action: "pushLeft", icon: "st.doors.garage.garage-closed", backgroundColor: "#79b821", nextState: "opening"
            state "open", label: 'Open', action: "pushLeft", icon: "st.doors.garage.garage-open", backgroundColor: "#ffa81e", nextState: "closing"
            state "opening", label: "Opening", icon: "st.doors.garage.garage-opening", backgroundColor: "89C2E8"
            state "closing", label: "Closing", icon: "st.doors.garage.garage-closing", backgroundColor: "89C2E8"
 		}
        standardTile("rightDoor", "device.rightDoor", width: 1, height: 1, canChangeIcon: true, canChangeBackground: true) {
			state "closed", label: 'Closed', action: "pushRight", icon: "st.doors.garage.garage-closed", backgroundColor: "#79b821", nextState: "opening"
            state "open", label: 'Open', action: "pushRight", icon: "st.doors.garage.garage-open", backgroundColor: "#ffa81e", nextState: "closing"
            state "opening", label: "Opening", icon: "st.doors.garage.garage-opening", backgroundColor: "89C2E8"
            state "closing", label: "Closing", icon: "st.doors.garage.garage-closing", backgroundColor: "89C2E8"
 		}

		main "leftDoor"
		details(["leftDoor","rightDoor"])
	}
    
    simulator {
        status "on":  "catchall: 0104 0000 01 01 0040 00 0A21 00 00 0000 0A 00 0A6F6E"
        status "off": "catchall: 0104 0000 01 01 0040 00 0A21 00 00 0000 0A 00 0A6F6666"
    
        // reply messages
        reply "raw 0x0 { 00 00 0a 0a 6f 6e }": "catchall: 0104 0000 01 01 0040 00 0A21 00 00 0000 0A 00 0A6F6E"
        reply "raw 0x0 { 00 00 0a 0a 6f 66 66 }": "catchall: 0104 0000 01 01 0040 00 0A21 00 00 0000 0A 00 0A6F6666"
    }
}
 
Map parse(String description) {
 	def name = null
	def value = zigbee.parse(description)?.text
    log.debug "Value is ${value}"
	def linkText = getLinkText(device)
	def descriptionText = getDescriptionText(description, linkText, value)
	def handlerName = value
	def isStateChange = value != "ping"
	def displayed = value && isStateChange
    
    def incoming_cmd = value.split()
    
    name = incoming_cmd[0]
    value = incoming_cmd[1]
    
	def result = [
		value: value,
        name: value != "ping" ? name : null,
		handlerName: handlerName,
		linkText: linkText,
		descriptionText: descriptionText,
		isStateChange: isStateChange,
		displayed: displayed
	]
 	log.debug result
	result
}
 
def pushLeft() {
    zigbee.smartShield(text: "pushLeft").format()
}

def pushRight() {
    zigbee.smartShield(text: "pushRight").format()
}

The Arduino Code is:

//*****************************************************************************
#include <SoftwareSerial.h>   //TODO need to set due to some weird wire language linker, should we absorb this whole library into smartthings
#include <SmartThings.h>

//*****************************************************************************
// Pin Definitions    | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
//                    V V V V V V V V V V V V V V V V V V V V V V V V V V V V V
//*****************************************************************************
#define PIN_LED           13
#define PIN_THING_RX      3
#define PIN_THING_TX      2
#define PIN_RIGHT         4
#define PIN_RIGHT_CONTACT 9
#define PIN_LEFT          7
#define PIN_LEFT_CONTACT  8
#define OPEN              HIGH
#define CLOSED            LOW
#define PUSH_DELAY      1000  // milliseconds to keep the button "pushed"

//*****************************************************************************
// Global Variables   | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
//                    V V V V V V V V V V V V V V V V V V V V V V V V V V V V V
//*****************************************************************************
SmartThingsCallout_t messageCallout;    // call out function forward decalaration
SmartThings smartthing(PIN_THING_RX, PIN_THING_TX, messageCallout);  // constructor

bool  leftClosed, rightClosed;

bool isDebugEnabled;    // 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  | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
//                  V V V V V V V V V V V V V V V V V V V V V V V V V V V V V V
//*****************************************************************************
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, 0, 2); // blue
  digitalWrite(PIN_RIGHT,LOW);
  delay(PUSH_DELAY);
  digitalWrite(PIN_RIGHT,HIGH);
  smartthing.shieldSetLED(0, 0, 0); // off
}

bool isClosed(int pin)
{
  return (digitalRead(pin) == CLOSED);
}

void updateDoorState()
{
  if (leftClosed != isClosed(PIN_LEFT_CONTACT))
  {
    leftClosed = isClosed(PIN_LEFT_CONTACT);
    if(leftClosed)
    {
      smartthing.send("leftDoor closed");
      Serial.println("leftDoor closed");
    } else {
      smartthing.send("leftDoor open");
      Serial.println("leftDoor open");
    }
  }
  if (rightClosed != isClosed(PIN_RIGHT_CONTACT))
  {
    rightClosed = isClosed(PIN_RIGHT_CONTACT);
    if(rightClosed)
    {
      smartthing.send("rightDoor closed");
      Serial.println("rightDoor closed");
    } else {
      smartthing.send("rightDoor open");
      Serial.println("rightDoor open");
    }
  } 
}

//*****************************************************************************
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, 0, 0); // red
        break;
      case STATE_JOINING:
        if (isDebugEnabled) Serial.println("JOINING");
        smartthing.shieldSetLED(2, 0, 0); // red
        break;
      case STATE_JOINED:
        if (isDebugEnabled) Serial.println("JOINED");
        smartthing.shieldSetLED(0, 0, 0); // off
        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, 0, 0); // red
        break;
      default:
      case STATE_UNKNOWN:
        if (isDebugEnabled) Serial.println("UNKNOWN");
        smartthing.shieldSetLED(0, 2, 0); // green
        break;
    }
    stateNetwork = tempState; 
  }
}

//*****************************************************************************
// API Functions    | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
//                  V V V V V V V V V V V V V V V V V V V V V V V V V V V V V V
//*****************************************************************************
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);
  
  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
  }

  // Get the Current State of the Doors
  Serial.println("Getting Door State...");
  if (isClosed(PIN_LEFT_CONTACT))
  {
    leftClosed = true;
    smartthing.send("leftDoor closed");
    Serial.println("leftDoor closed");
  } else {
    leftClosed = false;
    smartthing.send("leftDoor open");
    Serial.println("leftDoor open");
  }
  
  delay(1000);
  
  if (isClosed(PIN_RIGHT_CONTACT))
  {
    rightClosed = true;
    smartthing.send("rightDoor closed");
    Serial.println("rightDoor closed");
  } else {
    rightClosed = false;
    smartthing.send("rightDoor open");
    Serial.println("rightDoor open");
  }

  
  
}

//*****************************************************************************
void loop()
{
  // run smartthing logic
  smartthing.run();
  
  // Check the open/closed state of the doors
  updateDoorState();
  
  // Code left here to help debut network connections
  setNetworkStateLED();
}

//*****************************************************************************
void messageCallout(String message)
{
  // 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();
  }
    
}
3 Likes

Great write up!

Very cool @Steve28. There’s no reason I couldn’t update this to work with a four channel relay to cover my three doors correct? I think there are enough pins available to do three doors, not sure about four.

http://www.amazon.com/SainSmart-4-CH-4-Channel-Relay-Module/dp/B0057OC5O8/ref=sr_1_1?s=electronics&ie=UTF8&qid=1393087629&sr=1-1&keywords=sainsmart+relay

I get how you’re using the reed switches, but how are they powered? They don’t have batteries, so you run mains to them? Or pull off the audrino power/ground?

Thanks again for the writeup. I know I could do a couple evolves, but this seems like a fun project to get into.

BTW: Did you think about making them multiple devices instead of a single device? Or would you need three separate shields/audruino’s to do that?

@jim_lewallen yeah, you could easily extend this to more doors. You don’t power the reed switches… If you look in my Arduino code, you see PIN_LEFT_CONTACT and PIN_RIGHT_CONTACT are set to be of type INPUT_PULLUP. So that means the arduino holds them at 5V through a weak current. So you connect that pin to one side of the reed switch, and the other side of the reed switch to ground, so when the reed closes, it connects the Arduino pin to ground…then the Arduino will read 0V on it. So in other words, when my door is closed, the Arduino will see 0V (or LOW). When the door is open, it sees 5V (or HIGH).

Btw, the reed switches just close when a magnet gets near it, so one piece of the reed is just a magnet and ther other side has three connections, common, normally open, and normally closed… So you connect the ground and arduion pins to the common and normally open terminals.

This is great! Thanks for taking the time for this write up. Is it possible to add presence awareness to this setup like the ridiculously automated garage door smartapp can and control each door?

@sgonsalves - you wouldn’t add the presence awareness to the device - you would do that with an app. This is simply a device controller, you then can use an app to control the device.

So, yes, you can write an app the triggers either the left or right door when a presence tag or mobile presence becomes present. You might want to look at at an “unlock when I arrive” or app to see how that’s done. Sorry I can’t be of more help at the moment - I only have my ipad and it’s too difficult to log in to the ide and find one. Let me know if you have trouble and I can show you more.

Ok, thanks @stevesell I’ll take a look. I’m assuming I have to enable “lock” on the device type capabilities settings? The “garage” appears as one device, how do I target the left or right door in the app?

@stevesell, I have a similar setup where both door tiles are housed within a single “device” and I’m not seeing how a smartapp could control each door…it seems the smartapp can only control the “main” device tile, which in your case would be “leftDoor”. Am I missing something?

@csader and @sgonsalves - When viewing the device tile, you press the gear in the upper right of the icon and it gives you the screen shot I show in the first post. You can see there I have two door icons, one for the left door and one for the right. So I can control either independently. When making the device, I made two custom commands “pushLeft” and “pushRight” You can see the code for them at the bottom of my device type code in the first post. So an app can target either door by sending my device the pushLeft or pushRight command.

To be able to pick this device in an app, here’s what you do. My device controller is called “garagedoor” - just note that whatever name you choose, you need to camel case it - so “My Device” becomes myDevice, “MyDevice” becomes mydevice, ett. Essentially regardless of the case you typed it in when you named it, the first whole word (defined as contiguous caracters) are lower case and then the first letter of each of the rest of the words are upper case. Anyway, here’s how I select the garage device in my apps:

preferences {
	section("Select the Garage Controller") {
		input "theGarage", "device.garagedoor", title: "Pick The Garage", required: true
        }
}

Then I can actuate the doors by:

theGarage.pushLeft()

I can check if they are open or closed like so:

	if (theGarage.currentLeftDoor == "open")
	{
		// Do something because it's open
	}

Hope this helps.

Thanks @stevesell ! I finally got around to connecting everything and can now manually control each door. I took a look at the “unlock when I arrive” app and modified it to target a specific door. I then looked at the “ridiculously automated garage door” app and tried to modify the code to control each door and add some more intelligence but I’m not having much success. Having a hard time wrapping my head around how to properly get the left/right door shield contact on the shield properly integrated in that app. Do you know if/how that app can be tweaked to work with this setup for each door?

Never mind, I think I figured it out :slight_smile:

@sgonsalves Please elaborate. Someone else might benefit from what you figured out.

@csader Here’s the modified code for the right garage door, I have another app for the left door…seems to be working well so far.

preferences {

	section("Garage door") {
		input "doorSensor", "capability.contactSensor", title: "Which sensor?"
		input "doorSwitch", "device.garagedoor", title: "Which switch?"
		input "openThreshold", "number", title: "Warn when open longer than (optional)",description: "Number of minutes", required: false
		input "phone", "phone", title: "Warn with text message (optional)", description: "Phone Number", required: false
	}
	section("Car(s) using this garage door") {
		input "cars", "capability.presenceSensor", title: "Presence sensor", description: "Which car(s)?", multiple: true, required: false
		input "carDoorSensors", "capability.accelerationSensor", title: "Car door sensor(s)", description: "Which car(s)?", multiple: true, required: false
	}
	section("Interior door (optional)") {
		input "interiorDoorSensor", "capability.contactSensor", title: "Contact sensor?", required: false
	}
	section("False alarm threshold (defaults to 10 min)") {
		input "falseAlarmThreshold", "number", title: "Number of minutes", required: false
	}
}

def installed() {
	log.trace "installed()"
	subscribe()
}

def updated() {
	log.trace "updated()"
	unsubscribe()
	subscribe()
}

def subscribe() {
	log.debug "present: ${cars.collect{it.displayName + ': ' + it.currentPresence}}"
	subscribe(doorSensor, "rightDoor", garageDoorContact)

	subscribe(cars, "presence", carPresence)
	subscribe(carDoorSensors, "acceleration", accelerationActive)

	if (interiorDoorSensor) {
		subscribe(interiorDoorSensor, "contact.closed", interiorDoorClosed)
	}
}

def doorOpenCheck()
{
	final thresholdMinutes = openThreshold
	if (thresholdMinutes) {
		def currentState = doorSensor.rightDoorState
		log.debug "doorOpenCheck"
		if (currentState?.value == "open") {
			log.debug "open for ${now() - currentState.date.time}, openDoorNotificationSent: ${state.openDoorNotificationSent}"
			if (!state.openDoorNotificationSent && now() - currentState.date.time > thresholdMinutes * 60 *1000) {
				def msg = ""${doorSwitch.displayName} has been open for ${thresholdMinutes} minutes"
				log.info msg
				sendPush msg
				if (phone) {
					sendSms phone, msg
				}
				state.openDoorNotificationSent = true
			}
		}
		else {
			state.openDoorNotificationSent = false
		}
	}
}

def carPresence(evt)
{
	log.info "$evt.name: $evt.value"
	// time in which there must be no "not present" events in order to open the door
	final openDoorAwayInterval = falseAlarmThreshold ? falseAlarmThreshold * 60 : 600

	if (evt.value == "present") {
		// A car comes home

		def car = getCar(evt)
		def t0 = new Date(now() - (openDoorAwayInterval * 1000))
		def states = car.statesSince("presence", t0)
		def recentNotPresentState = states.find{it.value == "not present"}

		if (recentNotPresentState) {
			log.debug "Not opening "${doorSwitch.displayName} since car was not present at ${recentNotPresentState.date}, less than ${openDoorAwayInterval} sec ago"
		}
		else {
			if (doorSensor.currentrightDoor == "closed") {
				openDoor()
				sendPush "Opening "${doorSwitch.displayName} due to arrival of ${car.displayName}"
				state.appOpenedDoor = now()
			}
			else {
				log.debug "door already open"
			}
		}
	}
	else {
		// A car departs
		if (doorSensor.currentrightDoor == "open") {
			closeDoor()
			log.debug "Closing "${doorSwitch.displayName} after departure"
			sendPush("Closing "${doorSwitch.displayName} after departure")
		}
		else {
			log.debug "Not closing "${doorSwitch.displayName} because its already closed"
		}
	}
}

def garageDoorContact(evt)
{
	log.info "garageDoorContact, $evt.name: $evt.value"
	if (evt.value == "open") {
		schedule("0 * * * * ?", "doorOpenCheck")
	}
	else {
		unschedule("doorOpenCheck")
	}
}

def interiorDoorClosed(evt)
{
	log.info "interiorContact, $evt.name: $evt.value"

	// time during which closing the interior door will shut the garage door, if the app opened it
	final threshold = 15 * 60 * 1000
	if (state.appOpenedDoor && now() - state.appOpenedDoor < threshold) {
		state.appOpenedDoor = 0
		closeDoor()
	}
	else {
		log.debug "app didn't open door"
	}
}

def accelerationActive(evt)
{
	log.info "$evt.name: $evt.value"

	if (doorSensor.currentrightDoor == "closed") {
		log.debug "opening door when car door opened"
		openDoor()
	}
}

private openDoor()
{
	if (doorSensor.currentrightDoor == "closed") {
		log.debug "opening door"
		doorSwitch.pushRight()
	}
}

private closeDoor()
{
	if (doorSensor.currentrightDoor == "open") {
		log.debug "closing door"
		doorSwitch.pushRight()
	}
}

private getCar(evt)
{
	cars.find{it.id == evt.deviceId}
}

I am using 1 garage not two what parts need to change? How do you wire it into the garage?

Steve,

Thank you for sharing the DeviceType code as well as the Arduino code. I am brand new to the SmartThings world and had the exact same idea as you (i.e. use an Arduino + Shield to create a Garage Door Sensor/Controller.) Your code will certainly save me a ton of time!

I have created a developer account and I have my Arduino/Shield connected to my hub running your Arduino sketch successfully. I also created a new DeviceType under my account using your Device code above. After changing the device type of my Arduino/Shield via the “MyDevices” + Edit feature to select my (actually yours) new custom DeviceType, I am hitting a slight bump in the road. When I tap on either of the two garage doors icons on my iPhone, I do not ever get a command issued to the Arduino. I have the Arduino Serial Monitor running and I can see the initial setup logging as shown below

setup…
Getting Door State…
leftDoor open
rightDoor open
UNKNOWN
JOINED
Received message: ''
Received message: ''
Received message: ''
Received message: ‘’

But I never receive a “pushLeft” or “pushRight” no matter how many times I press the tiles. I have tried killing the iPhone app and restarting it, I have pulled down the Arduino app in the Arduino device view to cause it to refresh, but nothing seems to allow the Server-Side Groovy code to send a message to the Arduino. I even added logging to groovy code to output a message to console log window if either tile is pressed, and I see nothing written to the log except

‎10‎:‎17‎:‎16‎ ‎PM: error java.lang.ArrayIndexOutOfBoundsException
‎10‎:‎17‎:‎16‎ ‎PM: debug Value is ping
‎10‎:‎16‎:‎13‎ ‎PM: error java.lang.ArrayIndexOutOfBoundsException
‎10‎:‎16‎:‎13‎ ‎PM: debug Value is ping

Do you have any tips for what I am doing wrong? There is not a lot of documentation that explains the Arduino Shield very well (at least none that I have found so far.)

Any help you can provide would be very welcome!

Thanks,

Dan

Steve,

Communications from the shield to the SmartThings cloud and then to my iPhone “Garage Door” application works fine. The state of the doors goes from Open to Closed based on the two digital input pins (8 & 9). So I know the Arduino and Shield are fine, and they are paired with my hub.

If I change MyDevice type to the “On/Off Shield” device, the I can tap the tile and it sends either “on” or “off” to the Shield properly. The Serial Monitor logs these incoming requests.

My only issue is that the Garage Door device will not send data to the Shield when I tap each garage door tile in the iOS App for some reason.

Any ideas what I am doing wrong? I have tried to “Publish” the new DeviceType to myself… No change. I feel like I am missing something very basic about creating a new Device Type… Although, if I copy the sample code in the IDE for the “On/Off Shield” device, it works properly (just like the official published On/Off Shield device.)

Thanks,

Dan

OK, for anyone curious…I managed to figure out what the problem was. It appears that when you copy and paste DeviceType Groovy code, you must first create the custom attributes (leftDoor & rightDoor) and the custom commands (pushLeft and pushRight) on the form where you initially create your new device type (along with your name, namespace, device type name, etc…) After doing this, I was finally able to get Steve’s Garage Door application to work as expected.

Hope this helps someone else in the future!

I’ve been using this setup for a while now and it works flawlessly. I’d like to be able to use the magnetic contact sensors that are connected to the Arduino shield with regular smartapps so they can be leveraged as regular door open/close contacts. Seeing as the left and right doors appear as things underneath the master tile, it’s not possible. @stevesell Do you know how/if I can have each door contact broken out as individual “Virtual Contacts”, or if there’s some other workaround to expose each door sensor to regular apps?

@sgonsalves I have been working on an Arduino project as well based on Steve’s original work. I now have created three “Device Types” and one “Smart App” plus the Arduino code to achieve something very similar to what you’re looking for. Each of the contact sensors (I have 6 currently) is exposed as either a Virtual Garage Door Tile (which accepts button presses and shows all four door states on its Garage Door Tile as well as having a traditional contact sensor tile for compatibility with other SmartApps) or a Virtual Contact Sensor for normal doors.

I have created an Arduino Device Type, a Virtual Garage Door Device Type, a Virtual Contact Sensor Device Type, and a Smart App to handle the multiplexing/demultiplexing between the Arduino and Virtual Devices. I have also modified Steve’s original Arduino code extensively, as I have added 4 other magnetic contact sensors to monitor traditional doors in my house.

Code can be found at https://gist.github.com/ogiewon

Let me know if you have any questions. I know I have been struggling for a while to try and figure this groovy language out. I am very grateful that others have been willing to share their code, so I feel it is only right that I try to help others as well.

One caveat - this is a work in progress. I have not installed my Arduino in my garage yet, but everything is working great on the workbench. I am planning on making some more optimizations to improve performance. One feature I added to the Arduino code was to send the door status updates to the ST Cloud every 30 seconds, if nothing had been sent within the past 30 seconds. This helps to ensure the tiles always have the correct values.

1 Like

Thanks, taking a look at it now. In order for me to use your virtual contact sensor code, do I need to revisit my current setup (stevesell’s device type and arduino code + the ridiculously automated garage door app modified to fire each door discreetly)? Not quite sure which pieces I need to use from your code and where to start.