Generic handler for legacy devices


#1

I’m trying to create a simple generic handler for a range of legacy devices (if something similar already exists, I’d appreciate a link). Actuators were pretty simple, but sensors have me stumped and seeking help. Please excuse the newbie questions.

The basic idea is that a simple script running on an always-on computer at the location acts as a bridge between ST and the legacy devices. This computer might be a small board (Raspberry Pi, Beaglebone, Odroid, CHIP), a server that primarily performs other functions (fileserver, webserver, PBX), or a normal workstation.

Most of these devices lack IP connectivity. Examples include an X10 USB interface (CM15A), a weather station with a serial port, or a relay driven directly by a port on the computer, e.g. an RPi GPIO pin or PC parallel port pin.

Some devices speak IP, but have no official API, e.g. an alarm panel with a web page that displays current status of all zones. A simple script would poll the page every second, compare current and previous results, and report any changes to ST.

Ideally, several scripting languages would be supported (python, perl, PHP, pick-your-poison); these are usually pre-installed on most Mac and Linux systems and are freely available and easily installed on Windows. The developer would choose whichever is most familiar.

Actuators were no trouble: the device type handler makes an HTTP request, which runs a CGI script (at the location) that issues the required command.

But I don’t understand how to make sensors work. There are several examples using poll(), but such schemes are incompatible with applications that need a response within one or two seconds. There are also examples using additional hardware in the path. I’d like to avoid that approach not only because of cost, reliability and complexity issues, but also so that presently unoccupied locations can start utilizing ST.

I was able to write a ‘web services’ SmartApp that accepts updates from a remote sensor and responds by issuing commands to remote actuators. However, that’s not a viable solution, because all the business logic would have to be in that app. What’s needed is a way for the remote sensor to fire events (so other apps can use it as a normal device). That ought to be simple, but it has me stymied:

The IDE allows me to enable OAuth in a device type handler, and it displays a corresponding Client ID and Secret. However, attempting to use said Client ID results in an error “Client <Client ID> is not associated with a SmartApp.” That is of course true, but I don’t understand why it should be an error. The ID seems valid in some sense, because changing one character results in a ‘500’ error instead. How does one use OAuth in a device handler?

Then, I tried calling sendEvent() from a web services SmartApp, but have been unable to cause any action. The documentation shows two signatures: void sendEvent(Map properties) and void sendEvent(Device device, Map properties). I would assume that if an app is connected with exactly one device, the first form would use that device. But if I try e.g. sendEvent(name: “contact”, value: newstate), although no error is flagged and execution continues with the next statement, the event never fires. Trying e.g. sendEvent(contact1, [name: “contact”, value: newstate]) results in a ‘no matching signature’ error. The only two-parameter examples I found for sendEvent use a device network ID for the first argument. Although deviceNetworkId is not documented as a property of Device, it does seem to exist and e.g. sendEvent(contact1.deviceNetworkId, [name: “contact”, value: newstate]) seems to be a valid call, but results in an internal null pointer exception. What am I doing wrong here? Or, is there a simple example of an incoming request triggering an event?

Thanks for taking the time to read this rambling post, and for any guidance you can offer.


(John S) #2

See my code examples for Presence sensor... device associated with local wifi - it’s doing essentially that by sensing device association with your local wifi AP as presence.

For sensors, you’ll want a single smartapp implementing an oauth REST endpoint, which has access to the “virtual sensors”.

You then write whatever scripts you want running on your local hardware which monitor the legacy sensors, and when they change values you use the REST endpoint to push the changed value to the virtual device inside of SmartThings. Everything else on the ST side will “just work” on value changes.


#3

@schettj, Many thanks for your help. I got it working!

In a nutshell:

  1. REST endpoints work only in SmartApps, not device handlers. Not clear why, but seems to be the case.
  2. sendEvent() works only in device handlers, not SmartApps. Not clear why, but seems to be the case.
  3. So, a bridge is needed for the SmartApp to tell the device handler to issue the sendEvent.
  4. You did this by implementing a command to set the attribute, even though a physical sensor could not have such (you can’t command a thermometer to set the temperature). Brilliant!

BTW, Wi-Fi based presence is essential for one of my locations, where friends often stay. They all connect to Wi-Fi, but I wouldn’t want to require each of them to install a presence app. This gives a way to tell when the place is occupied, e.g. to alert me if they’ve gone but left the air conditioner running.

Thanks again.


(John S) #4

Awesome, glad to hear it! Your nutshell is spot on.