Ok, cleaned up a few things, setup the proper delays for doors to open (about 13 seconds so I gave it 14), and now I’m using A0,A1,A2 for reading out true door states. I’ll post it on GitHub but for now just wanted to share here. I also rearranged the tiles a bit for one main door and two side doors.
ARDUINO
//*****************************************************************************
/// @file
/// @brief
/// Arduino SmartThings Shield LED Example
/// @note
/// ______________
/// | |
/// | SW[] |
/// |[]RST |
/// | AREF |--
/// | GND |--
/// | 13 |-- X LED
/// | 12 |--
/// | 11 |--
/// --| 3.3V 10 |-- X_THING_RX FIX
/// --| 5V 9 |-- DOOR_THREE
/// --| GND 8 |-- DOOR_TWO
/// --| GND |
/// --| Vin 7 |-- DOOR_ONE
/// | 6 |--
/// Reed Door 1 --| A0 5 |--
/// Reed Door 2 --| A1 ( ) 4 |--
/// Reed Door 3 --| A2 3 |-- X THING_RX
/// --| A3 ____ 2 |-- X THING_TX
/// --| A4 | | 1 |--
/// --| A5 | | 0 |--
/// |____| |____|
/// |____|
///
//*****************************************************************************
#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_THING_RX 10
#define PIN_THING_RX_RESERVE 3
#define PIN_THING_TX 2
#define PIN_DOOR_ONE 7
#define PIN_DOOR_TWO 8
#define PIN_DOOR_THREE 9
#define PIN_DOOR_ONE_REED A0
#define PIN_DOOR_TWO_REED A1
#define PIN_DOOR_THREE_REED A2
//*****************************************************************************
// 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 isDebugEnabled; // enable or disable debug in this example
int door_one_state;
int door_two_state;
int door_three_state;
unsigned long currTime;
//*****************************************************************************
// 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 door_one(int cmd)
{
int changed = 0;
if (cmd == 1 && door_one_state == 0) {
door_one_state = 1;
changed = 1;
}
else if (cmd == 0 && door_one_state == 1) {
door_one_state = 0;
changed = 1;
}
if (changed == 1) {
smartthing.shieldSetLED(0, 3, 1);
digitalWrite(PIN_DOOR_ONE, HIGH); // press button
delay(780);
digitalWrite(PIN_DOOR_ONE, LOW); // unpress button
smartthing.shieldSetLED(0, 0, 0);
delay(14000); //delay sending final state until door should be in final state
if (cmd == 1) {
smartthing.send("door_one_open");
}
else
{
smartthing.send("door_one_close");
}
delay(500); // don't want to send new states without some delay between
validateDoorStates(false);
}
}
void door_two(int cmd)
{
int changed = 0;
if (cmd == 1 && door_two_state == 0) {
door_two_state = 1;
changed = 1;
}
else if (cmd == 0 && door_two_state == 1) {
door_two_state = 0;
changed = 1;
}
if (changed == 1) {
smartthing.shieldSetLED(3, 0, 2);
digitalWrite(PIN_DOOR_ONE, HIGH); // press button
delay(780);
digitalWrite(PIN_DOOR_ONE, LOW); // unpress button
smartthing.shieldSetLED(0, 0, 0);
delay(14000); //delay sending final state until door should be in final state
if (cmd == 1) {
smartthing.send("door_two_open");
}
else
{
smartthing.send("door_two_close");
}
delay(500); // don't want to send new states without some delay between
validateDoorStates(false);
}
}
void door_three(int cmd)
{
int changed = 0;
if (cmd == 1 && door_three_state == 0) {
door_three_state = 1;
changed = 1;
}
else if (cmd == 0 && door_three_state == 1) {
door_three_state = 0;
changed = 1;
}
if (changed == 1) {
smartthing.shieldSetLED(5, 1, 5);
digitalWrite(PIN_DOOR_ONE, HIGH); // press button
delay(780);
digitalWrite(PIN_DOOR_ONE, LOW); // unpress button
smartthing.shieldSetLED(0, 0, 0);
delay(14000); //delay sending final state until door should be in final state
if (cmd == 1) {
smartthing.send("door_three_open");
}
else
{
smartthing.send("door_three_close");
}
delay(500); // don't want to send new states without some delay between
validateDoorStates(false);
}
}
//*****************************************************************************
// 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;
// setup hardware pins
smartthing.shieldSetLED(0, 0, 0);
for (int i=PIN_DOOR_ONE; i <= PIN_DOOR_THREE; i++){
pinMode(i, OUTPUT);
digitalWrite(i, LOW);
}
pinMode(PIN_DOOR_ONE_REED, INPUT_PULLUP);
pinMode(PIN_DOOR_TWO_REED, INPUT_PULLUP);
pinMode(PIN_DOOR_THREE_REED, INPUT_PULLUP);
// Reed out the true states of the doors and init the cloud states for thingShield
validateDoorStates(true);
currTime = millis();
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();
// for every Nth time through this loop, validate the door states are valid per the physical switches
if (millis() >= currTime + 2000) {
validateDoorStates(false);
smartthing.shieldSetLED(5,0,0);
delay(500);
smartthing.shieldSetLED(0,0,0);
currTime = millis();
}
}
//*****************************************************************************
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("door_one_open"))
{
door_one(1);
}
else if (message.equals("door_one_close"))
{
door_one(0);
}
else if (message.equals("door_two_open"))
{
door_two(1);
}
else if (message.equals("door_two_close"))
{
door_two(0);
}
else if (message.equals("door_three_open"))
{
door_three(1);
}
else if (message.equals("door_three_close"))
{
door_three(0);
}
}
void validateDoorStates (bool forceSend) {
int tmp_door_one = door_one_state;
int tmp_door_two = door_two_state;
int tmp_door_three = door_three_state;
door_one_state = digitalRead(PIN_DOOR_ONE_REED) == HIGH? 1:0;
door_two_state = digitalRead(PIN_DOOR_TWO_REED) == HIGH? 1:0;
door_three_state = digitalRead(PIN_DOOR_THREE_REED) == HIGH? 1:0;
if ((door_one_state != tmp_door_one) || (forceSend == true)) {
if (door_one_state == 1) {
smartthing.send("door_one_open");
} else {
smartthing.send("door_one_close");
}
delay(500); // don't want to send new states without some delay between
}
if ((door_two_state != tmp_door_two) || (forceSend == true)) {
if (door_two_state == 1) {
smartthing.send("door_two_open");
} else {
smartthing.send("door_two_close");
}
delay(500); // don't want to send new states without some delay between
}
if ((door_three_state != tmp_door_three) || (forceSend == true)) {
if (door_three_state == 1) {
smartthing.send("door_three_open");
} else {
smartthing.send("door_three_close");
}
delay(200); // don't want to send new states without some delay between
}
}
SMARTTHINGS DEVICE HANDLER (ThingShield)
/**
* Copyright 2016 Justin Eltoft
*
* 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.
*
*/
metadata {
definition (name: "Garage Door Shield", namespace: "jdeltoft", author: "Justin Eltoft") {
capability "Actuator"
//capability "Switch"
capability "Sensor"
capability "Garage Door Control"
capability "Door Control"
//attribute "door_one", "enum", ["door_one_open", "door_one_close"]
//attribute "door_two", "enum", ["door_two_open", "door_two_close"]
//attribute "door_three", "enum", ["door_three_open", "door_three_close"]
attribute "door_one", "string"
attribute "door_two", "string"
attribute "door_three", "string"
command "door_one_open"
command "door_one_close"
command "door_two_open"
command "door_two_close"
command "door_three_open"
command "door_three_close"
}
// Simulator metadata
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"
}
// UI tile definitions
// Is there a way to prevent any tile press if one of the three tiles here is in the transition "next" state? I know the given tile in that transition state is locked but the others aren't
tiles(scale: 2) {
standardTile("door_two", "device.door_two", width: 6, height: 3, canChangeIcon: true, canChangeBackground: true, decoration: "flat") {
state "door_two_open", label: 'Main', action: "door_two_close", icon: "st.doors.garage.garage-open", backgroundColor: "#79b821", nextState:"closing"
state "door_two_close", label: 'Main', action: "door_two_open", icon: "st.doors.garage.garage-closed", backgroundColor: "#ffffff", nextState:"opening"
state("opening", label:'Opening', icon:"st.doors.garage.garage-opening", backgroundColor:"#ffe71e")
state("closing", label:'Closing', icon:"st.doors.garage.garage-closing", backgroundColor:"#ffe71e")
}
standardTile("door_one", "device.door_one", width: 3, height: 3, canChangeIcon: true, canChangeBackground: true, decoration: "flat") {
state "door_one_open", label: 'Left', action: "door_one_close", icon: "st.doors.garage.garage-open", backgroundColor: "#79b821", nextState:"closing"
state "door_one_close", label: 'Left', action: "door_one_open", icon: "st.doors.garage.garage-closed", backgroundColor: "#ffffff", nextState:"opening"
state("opening", label:'Opening', icon:"st.doors.garage.garage-opening", backgroundColor:"#ffe71e")
state("closing", label:'Closing', icon:"st.doors.garage.garage-closing", backgroundColor:"#ffe71e")
}
standardTile("door_three", "device.door_three", width: 3, height: 3, canChangeIcon: true, canChangeBackground: true, decoration: "flat") {
state "door_three_open", label: 'Right', action: "door_three_close", icon: "st.doors.garage.garage-open", backgroundColor: "#79b821", nextState:"closing"
state "door_three_close", label: 'Right', action: "door_three_open", icon: "st.doors.garage.garage-closed", backgroundColor: "#ffffff", nextState:"opening"
state("opening", label:'Opening', icon:"st.doors.garage.garage-opening", backgroundColor:"#ffe71e")
state("closing", label:'Closing', icon:"st.doors.garage.garage-closing", backgroundColor:"#ffe71e")
}
main ('door_two')
details (['door_two', 'door_one', 'door_three'])
}
}
def installed() {
log.trace "installed function was called"
//initialize()
}
def updated() {
log.trace "updated function was called"
//initialize()
}
def initialize() {
log.trace "initialize function was called"
}
def refresh() {
log.trace "refresh function was called"
}
// Parse incoming device messages to generate events
def parse(String description) {
//log.debug "Parsing '${description}'"
def value = zigbee.parse(description)?.text
def name
//log.trace "testing $value"
if (value in ["door_one_open","door_one_close"]) {
name = "door_one"
} else if (value in ["door_two_open","door_two_close"]) {
name = "door_two"
} else if (value in ["door_three_open","door_three_close"]) {
name = "door_three"
} else {
name = null
}
def result = createEvent(name: name, value: value)
log.debug "Parse returned ${result?.descriptionText}"
return result
}
def door_one_open() {
zigbee.smartShield(text: "door_one_open").format()
}
def door_one_close() {
zigbee.smartShield(text: "door_one_close").format()
}
def door_two_open() {
zigbee.smartShield(text: "door_two_open").format()
}
def door_two_close() {
zigbee.smartShield(text: "door_two_close").format()
}
def door_three_open() {
zigbee.smartShield(text: "door_three_open").format()
}
def door_three_close() {
zigbee.smartShield(text: "door_three_close").format()
}