Particle HTTP Post button and history with New ST App

Hello ST community!

This new ST app has broken a DYI pet feeder I made using a particle photon to control a servo in a box that releases food. My objective is to fix my device as it appears in my ST app to show that the photon is online, have a button to release food, and get the built in history functioning so I can see when the feeder last ran. I used an actuator device type that makes the http post needed to execute the feeding process. In the new app, this button is gone now! How would I re-write this to bring back a button, indicate the photon is connected, and have the built in history functioning?

THANK YOU SO MUCH!

Here is the current device handler Im using.

/**
 *  Cat Feeder Device Handler for SmartThings
 *  Author: Chris Kulakowski
 */
 
preferences {
section("Your Particle credentials and device Id:") {
    input("token", "text", title: "Access Token")
    input("deviceId", "text", title: "Device ID")
}
}
 
// for the UI
metadata {
	definition (name: "Cat Feeder Called by Button", namespace: "custom", author: "Chris Kulakowski") {
		command "feed"
    capability "actuator"
	}

// tile definitions
	tiles {
		standardTile("feeder", "device.actuator", width: 3, height: 3, canChangeIcon: true) {
			state "default", label: "Feed", action: "feed", icon: "st.shields.shields.pet-feeder", backgroundColor: "#ffffff"
		}
		main "feeder"
		details "feeder"
	}
}

def parse(String description) {
	log.error "This device does not support incoming events"
	return null
}

def feed() {
	sendToDevice "bfeed"
}

private sendToDevice(cmd) {
// Particle API call to photon device
// "deviceId" will be replaced with our actual device name
// feed is the name of our published function exposed by the device
	httpPost(
		uri: "https://api.particle.io/v1/devices/${deviceId}/feed",
    body: [access_token: token, command: cmd],  
	) {response -> log.debug (response.data)}
}

Hello, @kulbozz

The quickest way to reintegrate your device today is by modifying a bit the Virtual Switch DTH and pasting your sendToDevice function inside the on function.

Check this example which you can implement to perform such Http Requests:

/**
 *  Test DTH for custom capabilities.
 */
metadata {
	definition ( ... ) {
        capability "Switch"
	}

	simulator {}

	tiles {}
}

def parse(String description) {}

def installed() {
	initialize()
}

def updated() {
	initialize()
}

private initialize() {
    off()
}

def on() {
    sendEvent(name: "switch", value: "on")
    // Call API
    httpRequest()
}

def off() {
    sendEvent(name: "switch", value: "off")
}

def httpRequest () {
    // Example "Hello World" Http Request
	httpPost(
		uri: "",
        contentType: "application/json",
        body: '{"message": "hello world"}'
	) {response -> log.debug (response.data)}
}

In addition, as the latest version of the SmartThings app is only supporting custom commands from Custom Capabilities, if you want to migrate your feed command properly and display it as a push button again, let me know and I can help you with this process.

Hi Erick, thank you for your help. I tried using your example and made a new device handler but its not showing up in my app. Also, yes if you can help me migrate my feed command to display as a push button that would be greatly appreciated! Also, how do I get the device usage history to show up within the device too? Thank you!

    metadata {
	definition (name: "Cat feeder testing button", namespace: "Custom", author: "CHRIS KULAKOWSKI", cstHandler: true){
        capability "Switch"
	}

	simulator {}

	tiles {}
}

def parse(String description) {}

def installed() {
	initialize()
}

def updated() {
	initialize()
}

private initialize() {
    off()
}

def on() {
    sendEvent(name: "switch", value: "on")
    // Call API
    httpRequest()
}

def off() {
    sendEvent(name: "switch", value: "off")
}

def httpRequest () {
	log.debug "Dispensing food"
	httpPost(
		uri: "https://api.particle.io/v1/devices/${deviceId}/feed",
        body: [access_token: token, command: bfeed],  
	) {response -> log.debug (response.data)}
}

Hi, @kulbozz

If you’re trying to create the virtual device through the “My Devices” section (specifying your DTH) and it is not appearing, try creating a Virtual/Simulated Switch instead, then at your DTH’s simulator, use it instead of the “Virtual” default choice.

Now, to get started with the feed command migration, please set up the SmartThings CLI, which has a helper tool to create custom capabilities easily with the following command:

smartthings capabilities:create

In addition, once you’ve started to create your custom capability, create an attribute, and you’ll be prompted to create a Setter command or not. This is important because even if enum/basic commands are supported, at this moment custom capabilities work reliably with setter associations.

As soon as finish your capability, let me know so we can move on with the development of your capabilities presentation.

Note: As mentioned at this announcement, once we’ve migrated your command into a custom capability, history events will be available again

Hi @erickv, I’m having a really hard time with getting the smartthings-cli to work. The auth via browser is not working and I can’t figure out how to setup the config with a personal access token either. I’m getting the errors:

[2020-12-06T12:39:55.067] [ERROR] login-authenticator - received “server_error” error when trying to authenticate
[2020-12-06T12:39:55.067] [ERROR] login-authenticator - Unexpected server error.

[2020-12-06T12:58:11.306] [ERROR] cli - caught error TypeError: Cannot read property ‘token’ of undefined

I wish the cli would make a local version of the custom capability so auth wasn’t a dependancy. Then I could just copy and paste the code into the IDE.

Your help is appreciated!

To avoid this error message, check this documentation to configure you SmartThings CLI. Also, you can use your personal access token with --token flag to authorize your requests, e.g.:

 smartthings devices --token <personal_access_token>

@erickv I set the personal access token using that command. now I get this message in the browser:

‘redirect_uri’ could not be validated

Nevermind, I got it! So now that I have a custom capability, how do I use it? And, did I make this correctly?

What I need is to obtain the status of the device (is it online or not) and the ability to issue http posts with 3 arguments sfeed, bfeed, vfeed so that I can see in the history when its fed by voice, fed by button press, or fed by a schedule.

Capability: ***********.petfeeder


Attributes: 
┌────────┬─────────┬────────┐
│ Name   │ Type    │ Setter │
├────────┼─────────┼────────┤
│ Status │ boolean │        │
└────────┴─────────┴────────┘

Commands: 
┌──────────────┬──────────────────────────┐
│ Name         │ Arguments                │
├──────────────┼──────────────────────────┤
│ DispenseFood │ bfeed: string (optional) │
│              │ sfeed: string (optional) │
│              │ vfeed: string (optional) │
│ isOnline     │ value: boolean           │
│ isOffline    │ value: boolean           │
└──────────────┴──────────────────────────┘
1 Like

Great job! You can begin testing your capability through the IDE Simulator. You just need to include the capability name with its namespace in your DTH and the command methods, e.g.:

definition( ... ) {
    capability "namespace.petfeeder"
}

def DispenseFood (String argument) {
    ....
}
...

Now, before moving into the development of the presentation, I’d like to suggest a few changes:

  • In order to keep things simple and let capabilities handle a single task, create another capability to provide the isOnline/isOffline status, and this capability can keep registering feed commands.
  • Update your capability’s attribute to support string values, because your DispenseFood command will return string command responses (check the Capabilities API for more details on your custom capabilities.).

Now, about presentations, I recommend you the List display type to command and display the different feed states, and the State or Switch (in case you want to manually set this state) to show the isOnline/isOffline status (for more info, check this documentation).

In the end, the presentation of your capability (focusing on your feed commands/states) may look like this example:

Please let me know if you have any other questions and don’t forget to share your results.

Hi @erickv - first, thank you for your patience in helping me. I am no developer and learning as we go. Second, is it ok to share my namespace? Wasn’t sure if this was sensitive info or not.

Here is the updated 2 custom capabilities. Did I configure them right?

Capability: fieldoften55628.petfeeder

Attributes: 
┌────────┬────────┬────────┐
│ Name   │ Type   │ Setter │
├────────┼────────┼────────┤
│ Status │ string │        │
└────────┴────────┴────────┘

Commands: 
┌──────────────┬──────────────────────────┐
│ Name         │ Arguments                │
├──────────────┼──────────────────────────┤
│ dispenseFood │ bfeed: string (optional) │
│              │ sfeed: string (optional) │
│              │ vfeed: string (optional) │
└──────────────┴──────────────────────────┘

Capability: fieldoften55628.petfeederstatus

Attributes: 
┌────────┬─────────┬───────────┐
│ Name   │ Type    │ Setter    │
├────────┼─────────┼───────────┤
│ Status │ boolean │ setStatus │
└────────┴─────────┴───────────┘

Commands: 
┌───────────┬────────────────┐
│ Name      │ Arguments      │
├───────────┼────────────────┤
│ isOnline  │ value: boolean │
│ isOffline │ value: boolean │
│ setStatus │ value: boolean │
└───────────┴────────────────┘

Here is where I am with the DTH code. I would like on the dashboard a button to execute “bfeed” and I would like to see the status “Online” or “Offline”. How will I go about getting the status from the device? I just want to see if its connected to the internet. I think I can do this with another httppost if that is an option. Is there an easier way? Now for each command in the detailView, I only need an actual button for the “bfeed” command. The other 2 commands I would like to execute via a schedule using smartthings (sfeed) and via Alexa voice command (vfeed). Hope this makes sense. If all three buttons will be there, that is fine, just not necessary. I am also not sure how the “petfeederstatus” capability fits in here. Thanks for your help!

/**
 *  Pet feeder capability
 *
 */
preferences {
    section("Your Particle credentials and device Id:") {
        input("token", "text", title: "Access Token")
        input("deviceId", "text", title: "Device ID")
    }
}

metadata {
	definition (name: "Pet feeder testing button", namespace: "fieldoften55628", author: "CHRIS KULAKOWSKI", cstHandler: true){
        capability "fieldoften55628.petfeeder"
        capability "fieldoften55628.petfeederstatus"
	}

	simulator {}

	tiles {
    }
}
{
	// This section will allow you to get
	// the current state of the capability.
	// However, there's no action permitted
	// here. Action will be available at the
	// detailView section.
	"dashboard": {
		"states": [
        	{
				"label": "{{Status.value}}"
                }
        ],
		"actions": [
        	{
            	"pushButton": {
                	"command": "dispenseFood",
                    "argument": "bfeed"
                 },
                 "state": {
                 	"value": "fieldoften55628.petfeederstatus",
                 }
			}
        ]
	}
	// This section will provide access to the
	// supported arguments/values that the capability
	// can display.
	// Each alternative will display an individual
	// option.
    "detailView": [
        {
            "label": "Feeder status:",
            "displayType": "list",
            "list": {
                "state": {
                    "label": "Status.value",
                    "value": "Status.value",
                    "alternatives": [
                        {
                            "key": "bfeed",
                            "value": "Fed by button"
                        },
                        {
                            "key": "vfeed",
                            "value": "Fed by voice command"
                        },
                        {
                            "key": "sfeed",
                            "value": "Fed by schedule"
                        }
                    ]
                },
                "command": {
                    "name": "dispenseFood",
                    "alternatives": [
                        {
                            "key": "bfeed",
                            "value": "Feed by button"
                        },
                        {
                            "key": "vfeed",
                            "value": "Feed by voice command"
                        },
                        {
                            "key": "sfeed",
                            "value": "Feed by schedule"
                        }
                    ]
                }
            }
        }
    ]
}

def dispenseFood () {
    log.debug "Dispensing food"
	httpPost(
		uri: "https://api.particle.io/v1/devices/${deviceId}/feed",
        body: [access_token: token, command: cmd],  
	) {response -> log.debug (response.data)}
}

Great!

Now, a few steps to get started with the presentation of your fieldoften55628.petfeeder capability:

  1. From your dth, remove the content that was at the GitHub gist (presentation.json) file.

  2. To simplify the definition of your capability, I recommend you to use the this JSON file, which prepares your command as a setter and centralize arguments to value.

  3. Also, to create the presentation of your capability, download this JSON file and run the commands specified at the bottom.

  4. Then, run the next commands, which will push the UI metadata into the server (Note: Get your dth Id at your dth’s URL.):

    // Generate the metadata configuration
    smartthings presentation:device-config:generate --dth <dth_id> --json --output config.json
    
    // Create/Post it into the server
    smartthings presentation:device-config:create --input config.json 
    
  5. Finally, update your dth. Copy-paste the vid and mnmn values from the latest output and place them in your dth’s definition. Also, update your setter command to interact properly with the SmartThings App, e.g.:

    definition ( ... , vid: "xxxxx-xxxxx-xxxxxx", mnmn: "SmartThingsCommunity") {...
    
    def dispenseFood (String argument) {
        // First, perform HTTP request to determine if
        // response is successful, then send device event.
        sendEvent(name: "Status", value: argument)
    }
    

Let me know when you’re ready to move on with your other capability.


UPDATE 2020-12-11

Regarding this step:

I’ve updated the JSON file to include the preferences you’ve shared in your previous post.

Hi @erickv, this is great, thank you so much for your help. I followed all these steps exactly and published it for testing. The List in the DetailView is working great, it successfully dispenses food, however on the dashboard the push button is not working for some reason. Also, in my ST app I tried to make a routine in order to schedule the pet feeder using the “Fed by Schedule” command, but when creating the routine it says “Only devices with available actions are shown” and I am not able to select the Pet Feeder to use in a routine. Is this because the detailView is a displayType of “list”? Would it work if we instead made 3 pushButtons on the detailView?

I’m also trying to understand your comment:

// First, perform HTTP request to determine if
// response is successful, then send device event.

… do you mean I should get the device status first? I can do that via an http Request but I’m not sure how to handle the results. See below my attempt at the setStatus setter command function in the dth.

/**
 *  Pet feeder capability
 *
 */
preferences {
    section("Your Particle credentials and device Id:") {
        input("token", "text", title: "Access Token")
        input("deviceId", "text", title: "Device ID")
    }
}

definition (name: "Pet Feeder", vid: "5ffb0c27-edf8-31ed-8e54-b207ca380a9e", mnmn: "SmartThingsCommunity") {
        capability "fieldoften55628.petfeeder"
        capability "fieldoften55628.petfeederstatus"
}

def dispenseFood (cmd) {
	// First, perform HTTP request to determine if
    // response is successful, then send device event.
	httpPost(
		uri: "https://api.particle.io/v1/devices/${deviceId}/feed",
        body: [access_token: token, command: cmd],  
	) {response -> log.debug (response.data)}
    sendEvent(name: "Status", value: argument)
}

def setStatus () {
	// Getting the device status
    // should return {"online":true,"ok":true}%   
	httpRequest(
		uri: "https://api.particle.io/v1/devices/${deviceId}/ping",
        body: [access_token: token, command: "-X PUT"],  
	) {response -> log.debug (response.data)}
    sendEvent(name: "Status", value: argument)
}

I can get the device status with a curl command like this, not sure how to do the httpRequest in groovy.

> $ curl https://api.particle.io/v1/devices/<deviceid>/ping \
>        -X PUT \
>        -d access_token=<access_token>

it returns back:
{"online":true,"ok":true}%

1 Like

Awesome! I’m glad that you’re having good results so far.

Regarding the pushButton, yes, we’re still having issues with this display type, however, this issue has been assigned and our development team is working on it. And unfortunately, this includes automations as well. We’ll keep you all updated regarding automations working with custom capabilities.


Now, regarding how to handle the pet feeder API response, you can do it by storing the status code or success response in a variable. See the following example:

def dispenseFood (cmd) {
    Integer statusCode // variable to save status code
    String responseData // variable to save detail of response

	httpPost(
		uri: "https://api.particle.io/v1/devices/${deviceId}/feed",
        body: [access_token: token, command: cmd],  
	) { response -> 
            statusCode = response.status // save status code
            responseData = response.data // save response detail
      }

    // Flow control
    if (statusCode == 200) {
        sendEvent(name: "Status", value: argument)
    }
    else {
        log.debug "Something went wrong: ${responseData}"
    }
    
}
1 Like

Hi @erickv, I update the code. The device is now showing offline indefinitely. I can’t use it any longer. Can you help me with that and with the custom capability for online status? Thank you!

@erickv, I figured out the issues above. So here’s where I am now; trying to get the history tab on the dashboard to display events and get the customCapability fieldoften55628.petfeederstatus integrated.

/**
 *  Pet feeder capability
 *
 */
preferences {
    section("Your Particle credentials and device Id:") {
        input("token", "text", title: "Access Token")
        input("deviceId", "text", title: "Device ID")
    }
}

definition (name: "Pet Feeder", vid: "5ffb0c27-edf8-31ed-8e54-b207ca380a9e", author: "chrisk", mnmn: "SmartThingsCommunity") {
        capability "fieldoften55628.petfeeder"
        capability "fieldoften55628.petfeederstatus"
}

def dispenseFood (cmd) {
    Integer statusCode // variable to save status code
    String responseData // variable to save detail of response

	httpPost(
		uri: "https://api.particle.io/v1/devices/${deviceId}/feed",
        body: [access_token: token, command: cmd],  
	) { response -> 
            statusCode = response.status // save status code
            responseData = response.data // save response detail
      }

    // Flow control
    if (statusCode == 200) {
        sendEvent(name: "Status", value: argument)
    }
    else {
        log.debug "Something went wrong: ${responseData}"
    }
  
}
def setStatus () {
	// Getting the device status
    // should return {"online":true,"ok":true}%   
	httpRequest(
		uri: "https://api.particle.io/v1/devices/${deviceId}/ping",
        body: [access_token: token, command: "-X PUT"],  
	) {response -> log.debug (response.data)}
    sendEvent(name: "Status", value: argument)
    // how to code if status is "online":true then set device status to Online
}