[OBSOLETE] Raspberry Pi Device Type

One other minor detail – I had to add ‘from time import sleep’ to the top of the python file. Otherwise it complains about the ‘sleep(0.1)’.

Well this is entertaining – it seems that there’s a problem with re-use of Device Network Ids.

As I mentioned above, after deleting everything and starting from scratch, I had problems until I moved the static IP.

Next, I kept the ‘Device Type’ in place and deleted the ‘Device’. After re-installing, the app wasn’t working any more. But this time, I saw logs from two devices … the old (zombie) one and the new one!

Note that there are two ‘Raspberry Pi’ instances, and the request and response messages have different values for the key on the left.

Clicking the first ‘Raspberry Pi’ shows the sender (new Device):

Clicking the second ‘Raspberry Pi’ shows the responses being processed by the old (zombie) Device:

So… I have to conclude that the response message received by the TCP/IP stack on the hub is being routed to the first Device that registered the DNI, and the routing doesn’t get updated when that device is deleted. And it doesn’t get updated when the new Device runs (perhaps related to the need to set the DNI manually in the IDE).

When I changed the port from 8000 to 8001, it still sends the responses to the zombie, until I manually changed the DNI in the IDE. Then it all works again, because the DNI is different, never used before:

So there is definitely a problem with setting the device network id in this code, and maybe a problem with the SmartThings cloud as well.

Repository updated. Thanks for the feedback.

I wonder if we need to implicitly delete the old device during the uninstall. See the bottom of this page under “Implicit Removal of Child Devices”. Maybe we need to make the Raspberry Pi app as a device manager app instead similar to the Sonos (connect) SmartApp.

That does look promising. Also, there is a mention of the need to use a SmartApp when using LAN.
http://docs.smartthings.com/en/latest/introduction/what-can-developers-do/smartapp-overview.html

I did try getting a SmartApp to pass the device network id without success, but that was last week, when everything was a mystery. Unlike now when it all makes perfect sense, ha ha.

Related – it looks like a SmartApp can call the runIn() method, which would allow for a callback after a respectable period to check for a response. That doesn’t seem to be available to devices. I’ve not figured out how to get a callback after a delay.

Also related, I made some changes to your code, to reduce activity log updates and add a feature:

  • Send values as integers - the temp/mem/utilization values are displayed as integers on the icons anyhow, and sending integers in the events reduces the number of changes in the activity log.
  • Set the switch state based on request/response timestamps. Store timestamps at POST and parse(). At POST, if the last request was later than the last response → set switch to ‘off’. Each parse() implies a response from a happy Pi, so set switch to ‘on’. When the Pi goes down, the on/off state will update on the next poll, or when the user presses ‘refresh’ again. Since the on/off state is stable (though delayed), triggers for push notifications would make sense.
  • Added a button to switch a device controlled by the pi, and use the response to confirm. A button press changes from ‘off’ to ‘>on’ (orange), and updates to ‘on’ (green) at the response from the Pi. Same for ‘on’ to ‘>off’ to ‘off’.

I’ll send you the changes later.

@JamesH, @NickW: Maybe a adding a SmartApp is the right approach. I have been trying to get delayed responses and callbacks from the Raspberry Pi in the Device Type and it doesn’t seem to work. Specifically, any response more than 5 seconds old is ignored, and ST requires your device handler code to complete in 20 seconds or it literally times it out.
The Raspberry Pi really needs an event callback (Ex: door opened) capability initiated from the Pi which could then be used to create any type of device with the Pi - Door Sensors, inexpensive IP Camera, Garage Door Controller and Monitor (I have the Controller part working already), Flood monitor, etc. (These events call be easily initiated in the loop() function of WebIOPi)
ST does reference Registering for Callbacks: If you’d like to hear back from a LAN connected device upon a particular event, you need to register for a callback. You can subscribe to an event of the device, passing the device your hubs IP address as well as a path to callback to subscribeAction()

@Garnet, I noticed that the WeMo Motion device uses that callback to receive upnp events. So using that would allow the webiopi/python code to send messages to the smartthings device.

I don’t know if webiopi can generate upnp events already, but presumably there must be a python module for upnp.

Thanks @JamesH. I have looked at this, but it may beyond my ability. I understand the concept of sever-sent events, but figuring how to really get this to work on Raspberry Pi is another thing. Thanks again though.

Excellent write up @NickW - it was easy to follow. I was up and running in an hour. Thank you for putting this together.

I’m hoping to wire this up to trigger a relay attached to a specific GPIO port. Similar project: https://www.youtube.com/watch?v=3Pikhq99q5E

Does anyone have a starting point or documentation of where I should look so I can rework Nick’s raspberry pi device type groovy code to expose one of the GPIO ports for output as a SmartThings Switch I can use in a SmartApp?

Thank you!

If I’m not mistaken the method would be to write a macro in Nick’s python script on github that sets a GPIO port for output and then sets the state to be on or off. Then program panel code in Nick’s raspberry pi device type groovy code to expose the macro as a switch that can be incorporated into a SmartApp?

@fattmox you are correct. Look at how Nick implemented the “Refresh” button.

I created multiple on/off switches, so I had to create a macro for each one. In the ST Device Type definition I just had the device call a function that in turn called the correct macro. (I didn’t mess with creating classes). So my crude code example is:

standardTile("light2", "device.switch2") {
		state "off2", label: '${name}',  action: "on2",
		state "on2",  label: '${name}', action: "off2"  }
...
def on2()
{
    def uri = "/macros/onLight2"
    postAction(uri)
}

And in the Python Server code on the Pi:

(My Pi Device is down, so I will edit/update this post when I can. Until then here is my approximation.)
@webiopi.macro
def onLight2():
    my_piface(Pin4, ON);  //Used library that controls Pis pins.  ON basically equals 1

-Hope this helps.

1 Like

Thanks for the great tips @Garnet. I’ve got it started but I can’t seem to call my action function. Currently all that’s in it is a log.debug message and a sendEvent to change the tile state.

I’ve declared by action function in the same place as the other action functions - are there any more pieces to getting the tile to launch the action function?

        standardTile("light2", "device.switch3") {
			state "off3", label: '${name}',  action: "on3"
			state "on3",  label: '${name}', action: "off3"  
        }
...
def on3() {
    log.debug "light on"
    sendEvent(name: "switch3", value: "on")
}
def off3() {
    log.debug "light off"
    sendEvent(name: "switch3", value: "off")
}

@fattmox: Yes…whoops. You have to add them as custom commands. (Refresh is already a default command in ST). So specifically:

command "on3"
command "off3"

I put mint in the “metadata {” section right after the custom capability definitions.

YES! That really stumped me for longer than I’d like to admit - thanks for tip - my actions are firing now.

To expose a switch other than the On/Off status (eg device.switch2) of the raspberry pi device type will I need to recreate it in a new device type?
When I go to my custom SmartApps and pick a switch the only one available to pick is the on/off switch, I’d rather not create a new device type for one switch.

Just add additional capabilities to your first device-type under the definition and metadata sections.

...
metadata {
definition (name: "Raspberry Pi", namespace: "nicholaswilde/smartthings", author: "Nicholas Wilde") {
    capability "Polling"
    capability "Refresh"
    capability "Temperature Measurement"
    capability "Switch"
    capability "Sensor"
    capability "Actuator"

    capability "Your new capability"

    attribute "cpuPercentage", "string"
    attribute "memory", "string"
    attribute "diskUsage", "string"
    command "restart"
}
...

Anatomy of a Device Type

One other thing I did to keep things “simple” for my Pi device was to use the built-in capability devices as Master/Virtual capability and then modify it based on my custom capability.
My problem: I had multiple sensors, but ST only uses triggers and IFTT to work with their default Sensor.
My solution: Created Sensor1 and Sensor2 as the actual Pi sensors. When either one of them changed status then the code inside the update would also update the status of the ST sensor. I called this sensor the Master Sensor and made it a 2x2 size tile.
Other solution: There is a better (more complex) solution in the community where you create virtual device(s) and control them with a SmartApp.

1 Like

@fattmox: You mentioned creating a new (2nd) device type for the RaspberryPi and I want to save you time and headaches. The TCP/IP connection to RaspberryPi appears to be like ST capabilities where only one is allowed - a singleton in SW terms.
I created some new capabilities in a 2nd device type and then tried to send messages to it with epic failure. It completely hosed up my Pi device. I would send messages from 1 device and the response was sent back to the second. I had to completely delete/uninstall both devices as ST was still trying to communicate with the old one even though it was deleted.
I also had major problems when I tried to add a 2nd RaspberryPi, but this may have been a coincidence.
Since I was not able to send periodic/random events (Door Open) from Pi to ST, I haven’t done much more.

Hope this helps in case you were still thinking about creating a 2nd Device Type.

1 Like

Thanks Nick, are you saying a device type can have multiple instances of a single capability such as ‘switch’. I’m hoping to add another 3 switches to your raspberry pi device type that I’ve wired up to a 8 channel relay board. I can make them in the interface no problem but I want to expose them to a smart app.

Good news. I was able to create virtual switches for all the child switched in my modified raspberry pi device type quite easily using @cooperglee’s solution posted here: Device with Multiple Switches - I ended up going straight to his github to download the code.
I added a template for usability. I’m still experiencing some funny behaviour in the ui where my custom switches don’t properly reflect the state of the GPIO that I’ll have to debug. However, I’ve now got switches I can incorporate into SmartApps!

I wired up my furnace last night and everything tested OK. I now have fan, force on and kill switch switches which operate inline/accessory with the existing configuration so it fall safes to original configuration. Exciting to see it all come together.