SmartThings and the Recirculating Pump

A couple of years ago, we got a recirculating pump to run the hot water line from the master bathroom back to the water heater so we could get actual hot showers. The pump came with a built-in timer so that we could schedule times for it to run. That’s swell if you live by the clock. But what if you take a shower at different times of day, or at times that are unpredictable? What you really want is a button or a switch in the bathroom (at one end of the house) that will turn on the pump (at the other end of the house) for long enough to get hot water (say, five minutes or so) and then turn it off.

Enter SmartThings. I actually found out about SmartThings from the channels list at IFTTT. I was looking at IFTTT to see if maybe I could make it turn on the stairwell light when we got close to the house. One could, if one had a SmartThings hub. So that’s where I started from, thinking about this pump problem. Got a hub, got a contact sensor, and got a switchable outlet. Now, to wire these things up so that the magic happens!

Only, I discovered that in order to apply any kind of logic to devices connected together with the SmartThings hub, I had to install a custom app into the hub. What? There’s a graphical display of all my devices, right there on my tablet, and I can’t drag a link from one to another? I can’t say, “Create new activity…” and get some basic logic wizard? WTF? Way to be dumb, SmartThings.

Okay, so here’s the solution: register as a SmartThings developer (it’s free) and write the logic in their almost-good web IDE. (I say, “almost good,” because it compiles on save and the only indication of syntax errors is that the save just never completes.) What language is it? Oh, you don’t need to know that. What are the keywords and operators? You don’t need to know that, either. (At least one error message mentioned Groovy, but I’m not sure if that’s the whole deal.) Anyway, I’ve now written an app that accepts a bunch of parameters (which contact sensor, which switch, what should the initial switch state be set to, what’s the final switch state, and how long is the countdown) and I’ve installed it in my house. Hooray! How do I share this app with the rest of the world? Beats me. Oh, wait, here’s the source!

/**
* Contact countdown
*
* Author: Stephen Beitzel <sbeitzel@pobox.com>
* Date: 2014-02-11
*/
// myContact - reference to the contact sensor that initiates the run
// mySwitch - reference to the switch we're controlling
// firstState - reference to the initial state of the switch
// finalState - reference to the final state of the switch
// delaySeconds - how long to wait

preferences {
  section("Initiate countdown from contact sensor") {
    input "myContact", "capability.contactSensor"
  }

  section("Initiate countdown on switch open") {
    input "mySwitch", "capability.switch"
  }

  section("Countdown this many seconds") {
    input name: "delaySeconds", title: "Seconds?", type: "number", multiple: false
  }

  section("Initial switch state") {
    input name: "firstState", title: "First set the switch to:", type: "bool", multiple: false
  }

  section("Final switch state") {
    input name: "finalState", title: "Upon reaching countdown, set switch to:", type: "bool", multiple: false
  }
}

def installed() {
  log.debug "Installed with settings: ${settings}"
  initialize()
}

def updated() {
  log.debug "Updated with settings: ${settings}"
  unsubscribe()
  initialize()
}

def initialize() {
  subscribe(myContact.contact)
  subscribe(mySwitch.switch)
}

def contact(evt) {
  log.debug "Contact event: ${evt.value}"
  if (evt.value == "open") {
    log.debug "Starting a new countdown"
    // set the switch
    if (firstState.value == true) {
      mySwitch.on()
    } else {
      log.debug("firstState.value is not equal to true, it is ${firstState.value}")
      mySwitch.off()
    }
    // schedule the countdown
    runIn(delaySeconds, countedDown)
  }
}

def countedDown() {
  log.debug "Counted down"
  if (finalState.value == true) {
    mySwitch.on()
  } else {
    mySwitch.off()
  }
}

Published by pirateguillermo

I play the bagpipes. I program computers. I support my family in their various endeavors, and I enjoy my wonderful life.

3 thoughts on “SmartThings and the Recirculating Pump

  1. Good post. I am glad you were able to get in and get this working via SmartApps. As a developer I feel your pain on the web-based IDE. While it is very cool and useful what you can do with it, it can certainly use improvement – among them the saving and error handling scenario you mentioned. It has also long been a goal of SmartThings to create the type of drag and drop interface you mention. We played with it over a year ago and found that for anything but the most basic scenarios (if this, then that NOT if this or this then that and that) the interface actually brought more complexity to bear. I think we’ll revisit this but just not in the immediate future. Anyway, thanks for the great post and sample code.

    1. Actually, back when I worked at Salamander Interactive (name later changed to DecisionPower) we built a general-purpose component based discrete event simulation environment that used exactly the drag-a-link method of hooking components together. Yes, it could get complicated. Even so, I managed to build a simple logic circuit to titrate a solution to a target pH with everything being quite easy to follow. But here are two things to remember:

      1. Most people aren’t looking to solve complicated problems. The simple solution will actually work for better than half of your customers.

      2. Programming is hard. Pretending that it isn’t hard is just foolish. The only way to present programming as easy is to ignore any possibility of complexity, which will frustrate everyone who doesn’t fall into the simple use case.

      Beyond the obvious UI problems in the SmartThings IDE, there’s the language reference problem. What are the reserved keywords? What are the operators? Can I do bitwise operations? What functions are available that are not part of some device? (For example, the only way I know that the ‘runIn’ method even exists is that it appears in one of the example apps; where is it documented? Oh, it’s not.)

      A graphical programming language doesn’t hide the complexity, but at least there’d be a palette of available operations, to show me what library methods exist. Yes, it could get very snarled, but really — if I’m trying to build something really snarled, it’s going to look ugly no matter whether it’s a drag and drop interface or a plain text interface. At least with a programming environment built into the control app I’d be able to solve simple problems myself without having to search for some program written by some random developer and possibly named something helpful.

      Oh yeah, and how come there’s a control app for my Android and iOS devices but there’s no control app for my laptop? Because, clearly, you expect me to be managing my house via the tiny screen on my phone and you don’t expect me to use the greater screen real estate on my actual computer. Big screens afford the space to spread out graphical components and make the complexity easier to manage. Take a look at Prograph, for instance, for another example of a graphical programming language that manages to handle complexity very nicely.

      All of this is to say, yes, you’ve got a hard set of problems to solve. But none of these problems are *new* problems — they’ve all been solved by smart people years ago. Go ahead and use those solutions. Document your stuff.

Leave a Reply