Is there a working example of a button subscription

I’ve tried to set up a handler to be called when a two-button device is pressed, both with using the rest API with json payloads, and using the SmartApp JS SDK. There are no errors reported and a call to the /subscriptions API confirms that a subscription has been set up, but I never get any events.

Does anyone know if there is a working example of a SmartApp successfully subscribing to a button?

Tech support has not pointed out anything I’m doing wrong according to the documentation.

But curiously, they won’t confirm to me that they know it does work for a fact.

Even more curiously, they say they cannot replicate my problem using the information I have provided them so far. Since my problem is that I am seeing no events being triggered, then by implication, it means that tech support are able to see events being triggered, so it strikes me as curious that they won’t confirm what they are seeing and show me what the payload looks like. Instead they keep asking me for more and more information so that they can replicate a scenario in which nothing happens…

So I wondered, if anyone out there knows of an instance where a button being pressed generated a call to an event handler.

Following is the /subscriptions output, which shows I have a motion sensor (which gives me events) and a button sensor (which does not) subscribed:

{
  "items": [
    {
      "id": "<...>",
      "installedAppId": "<installed app id>",
      "sourceType": "DEVICE",
      "device": {
        "deviceId": "<button id>",
        "componentId": "button2",
        "capability": "button",
        "attribute": "button",
        "value": "*",
        "stateChangeOnly": true,
        "subscriptionName": "myButtonEventHandler_0",
        "modes": [
        ]
      }
    },
    {
      "id": "<...>",
      "installedAppId": "<installed app id>",
      "sourceType": "DEVICE",
      "device": {
        "deviceId": "<motion detector id>",
        "componentId": "main",
        "capability": "motionSensor",
        "attribute": "motion",
        "value": "*",
        "stateChangeOnly": true,
        "subscriptionName": "myMotionEventHandler_0",
        "modes": [
        ]
      }
    }
  ],
  "_links": {
  }
}

(BTW, the reason I wanted to see the payload in the case where tech support said they were not able to replicate the non-occurrence of an event, was that I am wondering about the available states documented for a button are like pressed, held, down (i.e. button2), up (i.e. button1), etc, but not released. On the other hand the motion sensor and the contact sensor have available states like active/inactive and open/closed. i.e. states that you could transition between. The button is a momentary action button, so whenever you query the state by polling it’s always pushed. So how does an event get reported, I wondered.)

You are subscribing to the button with ‘stateChangeOnly’ set to true, but a typical simple button might only send ‘pushed’ events so there isn’t a state change. Although I haven’t tried it myself yet, I would expect you to need ‘stateChangeOnly’ to be false as you just want whatever events are generated.

On the device handler end, button events are created with ‘isStateChange: true’ which forces them to always be propagated even though the value hasn’t changed. I guess the subscriptions have an extra filter.

It should be pointed out that device handlers generate events, they do not change the device attributes directly. So the button attribute is set to ‘pushed’ because a ‘pushed’ event was created, not the other way around.

1 Like

I know this is going to sound weird, but in most home automation systems a button is not an actuator, it’s a sensor. It’s reporting that there was a physical press. Just like a pressure mat would do. A switch, on the other hand, is considered an actuator. That’s why a switch typically has state and a button doesn’t. It’s also why you can turn on a switch from the network but you can’t “turn on“ a physical button device from the network.

I know that feels odd if you haven’t been through the formal architecture materials, but it’s really common, it’s not a smartthings decision. It goes back to some early IEEE decisions About device class definitions.

Sadly, it seems by the time SmartThings realised that ‘attribute’ was a much better word to use than ‘state’, the genie was long since out of the bottle. So an ‘attribute’ represents e.g. the last reported (and hopefully current) state of a switch, the last action of a button, and the last value reported by a thermometer. It just gets called the ‘state’ all over the place.

1 Like

I have now tested this out for myself. Having written all that stuff earlier, I found that could receive a button push event just fine, even with ‘stateChangeOnly = true’. That was using the ‘main’ component.

1 Like

Thanks @orangebucket! I think I tried all the various possibilities given by the documentation (stateChangeOnly=true/false, name/wildcard, button1/button2/main), basically everything the /device query came back with. If I said one value didn’t work, tech support’s algorithm basically said try the other.

But since you have confirmed (something that tech support for some reason could not) that it is a working thing, rather than vapour-ware, I will try that again.

Could I ask you to share the json for the /subscriptions query, and the payload received by the event handler?

I should also share that my button is IKEA Type E1743 TRADFRI ON/OFF Switch in case it’s relevant. It’s Zigbee.

Hello @wtsang01,

Please see below the code snippet to create the subscriptions and print the events when they are received.

// SmartApp init
const testSmartApp = new SmartApp();

// SmartApp definition
testSmartApp.appId('SmartApp example')
  // Uncomment to check logs.
  // .enableEventLogging(2)
  .disableCustomDisplayName(true)
  .permissions(['r:devices:*', 'r:locations:*'])
  .page('mainPage', (ctx, page, configData) => {
    page.complete(true)
      .name('Button monitor')
    // Devices input section
    page.section('Button devices:', section => {
      section.deviceSetting('buttonDevices')
        .name('')
        .description('Tap to select')
        .capabilities(['button'])
        .required(true)
        .multiple(true)
        .permissions('rx')
    })
  })
  .updated(async (context, updateData) => {
    // Clear subscription to avoid duplication
    await context.api.subscriptions.unsubscribeAll();
    // Create/Update subscriptions
    await context.api.subscriptions.subscribeToDevices(
      context.config.buttonDevices, '*', '*', 'buttonSubscription'
    );
  })
  .subscribedDeviceEventHandler('buttonSubscription', async (context, event) => {
    console.log(event);
  });

Please note it is created using the SmartThings NodeJS SDK.

Let us know if you have any questions.

I had a suspicion that was what you might be using. I’ll try with one of those in the morning. I only started playing with the Webhook Endpoint apps yesterday so I am on a learning curve. I’m also using PHP and doing it all from scratch as I just prefer good old procedural programming …

1 Like

Thanks @orangebucket really appreciate the “I’ll suggest something AND do what I suggest too” approach, which unfortunately doesn’t seem to apply to tech support…

I’m only evaluating different platforms for now while I get up to speed with the Home Automation world, and trying to identify what shows promise for my purposes. So I’m just testing the combo of quality, documentation and level of support. The other excuse I have is that I never really grew up from when I was a kid and took my parents’ gadgets apart just to see how they worked!

Thanks for the code @nayelyz! As you might have read, one of my approaches was with the SmartApp SDK, so at first glance my code looks very similar, but for intellectual rigour and honesty I will, of course, actually run it and hopefully it will work. What type of device did you use and what was the payload that you got back in the handler? And the listing from the /subscriptions response?

OK …

The Ikea On/Off buttons (known as Wireless Dimmers if you are reading the catalogue instead of the back of the button) are implemented as a component device. The ‘main’ component has both the ‘Button’ and the long since deprecated ‘Holdable Button’ capability which share the same ‘button’ attribute. The ‘button1’ and ‘button2’ components likewise have the ‘Button’ and ‘Holdable Button’ capabilities. The ‘main’ component, the parent device, implements the old style handling of multiple buttons where a ‘buttonNumber’ is added to the event data (the same trick gets used for multiple presses and things in older handlers and apps).

I authorised an Ikea button using just the parent/main component, choosing just read permissions, and used wildcards to subscribe to it to see what turned up (I chose to do this in the UPDATE lifecycle):

{
    "sourceType": "DEVICE",
    "device": {
        "deviceId": "UUID",
        "componentId": "*",
        "capability": "*",
        "attribute": "*",
        "value": "*"
    }
}

Reading back the subscriptions gave me (redacted and slightly trimmed top and bottom):

       {
            "id": "UUID",
            "installedAppId": "UUID",
            "sourceType": "DEVICE",
            "device": {
                "deviceId": "UUID",
                "componentId": "main",
                "capability": "*",
                "attribute": "*",
                "value": "*",
                "stateChangeOnly": true,
                "modes": []
            }
        }

I then pressed a button, and got SIX events returned, which I logged (in the form: ‘component capability attribute value’ as:

[10-Jun-2020 10:20:57 Europe/London] button2 holdableButton button pushed
[10-Jun-2020 10:20:57 Europe/London] button2 button button pushed
[10-Jun-2020 10:20:57 Europe/London] main button button pushed
[10-Jun-2020 10:20:57 Europe/London] main button button pushed
[10-Jun-2020 10:20:57 Europe/London] main holdableButton button pushed
[10-Jun-2020 10:20:57 Europe/London] main holdableButton button pushed

I imagine ‘button’ and ‘holdableButton’ turn into two events because they share the same attribute name. I don’t really know what ‘holdableButton’ is even doing in the device handler.

I am not entirely sure why all the ‘main’ events double up. From what I can see they are pretty useless anyway as the event doesn’t seem to carry the ‘buttonNumber’ data.

A trimmed and redacted sample of the event data received is:

{
    "lifecycle": "EVENT",
    [ ... SNIP ...[
    "eventData": {
        "AuthToken": "REALLY LONG TOKEN"
        "installedApp": {
            "installedAppId": "UUID",
            "locationId": "UUID",
            "config": {
                "thebutton": [
                    {
                        "valueType": "DEVICE",
                        "deviceConfig": {
                            "deviceId": 'UUID",
                            "componentId": "main"
                        }
                    }
                ]
            }
            "permissions": [
                "R: devices: UUID"
            ]
        }
        "events": [
            {
                "eventTime": "2020-06-10T09: 20: 57Z",
                "eventType": "DEVICE_EVENT",
                "deviceEvent": {
                    "eventId": "UUID",
                    "locationId": "UUID",
                    "deviceId": "UUID",
                    "componentId": "main",
                    "capability": "holdableButton",
                    "attribute": "button",
                    "value": "pushed",
                    "valueType": "string",
                    "stateChange": true,
                    "date": [],
                    "subscriptionName": "UUID"
                }
            }
        ]
    }
    "settings": []
}

Having seen all that, I then changed to using two individual subscription requests for just the components of the buttons, using the form:

{
    "sourceType": "DEVICE",
    "device": {
        "deviceId": "UUID",
        "componentId": "button2",
        "capability": "button",
        "attribute": "button",
        "value": "*"
    }
}

That cleans things up rather nicely, as here are the events from pressing and holding both buttons:

[10-Jun-2020 10:38:13 Europe/London] button1 button button pushed
[10-Jun-2020 10:38:18 Europe/London] button2 button button pushed
[10-Jun-2020 10:38:22 Europe/London] button1 button button held
[10-Jun-2020 10:38:26 Europe/London] button2 button button held

Here is a clip of the received data for the last one of those:

        "events": [
            {
                "eventTime": "2020-06-10T09:38:26Z",
                "eventType": "DEVICE_EVENT",
                "deviceEvent": {
                    "eventId": "UUID",
                    "locationId": "UUID",
                    "deviceId": "UUID",
                    "componentId": "button2",
                    "capability": "button",
                    "attribute": "button",
                    "value": "held",
                    "valueType": "string",
                    "stateChange": true,
                    "data": [],
                    "subscriptionName": "UUID"
                }
            }

I am still pondering ‘stateChangeOnly’. I think on reflection it must be plumbed in earlier than I imagined and be respecting the device handlers declaring the button presses as state changes.

2 Likes

Fantastic @orangebucket! I’m not entirely sure if I can see what I’m doing differently, but it gives me hope (which tech support never gave me) that it’s known to work. So my effort will less likely be misdirected in finding my own mistake.

I’ll try this later today!

1 Like

I think I have solved the problem! Or rather “understand it better”!

So it wasn’t the JS code, and it wasn’t the way I was using the REST API.

Here is the investigation, pruned of all the fruitless diversionary paths:

  1. In desperation, I decided to start all over again. Factory reset my IKEA button (4 quick presses on the pairing button under the back cover), removed all trace of the button from Smartthings, including apps and automations which may have referred to it.

  2. Paired the button with the hub in accordance with the instructions on the app (4 quick presses on the pairing button, while the hub was searching for it). Success! Button tile appears on App.

  3. Pressed a button. Something I don’t think I’d seen before - the tile status text changed from “standby” to “pressed” and back to “standby”!

  4. Installed and configured my testing SmartApp and started receiving events! Problem solved!

So it must have lost it’s pairing with the hub, although the app was still showing the tile, allowing me to create automations based on it, and allowing me to refer to it in SmartApp and REST API calls…But the fact that the system knew about the button was evidence was that it must have been paired at some stage. So how can it lose it’s pairing? Then I realised I hadn’t finished restoring my setup to it’s previous state. I hadn’t paired it with my IKEA light.

  1. Followed the instructions according to IKEA. Held the button near the light and held the pairing button down until the light dimmed and brightened to acknowledge. Success. Can now control the light with the button.

  2. Went back to Smartthings. No more events triggered. No more response from the button tile. Problem replicated!

Now before all the defenders of the faith leap to Smartthings defence, and say “you unpaired it! That’s why it won’t talk to Smartthings again”, I would make the following points:

a. I didn’t unpair it. According to IKEA a button (steering device) is capable of talking to more than one device. 4 quick presses on the paring button resets all pairing. A long press requests to add a pairing.

b. Zigbee NWK layer fully supports multiple destinations.

c. Why does Smartthings ask for a reset of the button as part of the pairing? In doing so, it is requiring that the button is removed from all existing pairings (so much for interoperability).

d) Question for both IKEA and Smartthings: when adding a pairing to a new light, why does it lose it’s pairing with the hub?

e) Definitely one for Smartthings developers: Why does the dead body of an unpaired button still show in the system long after it’s gone? If a light is powered off or unreachable, it comes up as offline. Why isn’t there any indication that a button hasn’t been heard from for a few months? Instead it still allows me to define it in my Automations and SmartApps, and shows the battery level at 37% (what happens when the battery is dead? Or removed?)

Nothing’s perfect, of course, so I thought I’d try to work with the known limitations. Immediate problem, if I still want it to control a light I’ll probably have to forget about the press-n-hold dimming, and accept that my lighting will only respond a second or so after a round trip to Europe.

Still, it’s allowed me to press on with my evaluation, and I must admit it raises some more questions, which should be the subject of new threads.

So I raised these threads to follow up:

https://community.smartthings.com/t/events-from-buttons/196946

https://community.smartthings.com/t/onboarding-ikea-tradfri-zigbee-button/196950

https://community.smartthings.com/t/zigbee-integration/196949

Because that’s the way it’s designed. You stopped using the remote to send messages through the hub and started using it to send them directly to the bulbs. That method is really intended for ZLL networks, not Zigbee 3.0, that is networks where there isn’t a hub at all.

Based on what @GSzabados Reported in one of your other threads, it sounds like the issue is specific to the two button model and that when you go to do the groupcast binding it is switching from a ZHA profile to a ZLL profile, where the remote assumes there isn’t a hub at all.

If you want to use the button with the hub, you should be using the hub to handle the messaging to the bulbs. If you want to just use the button as a parallel means of control, then you can bind the individual bulbs to the button. Just be aware that smartthings doesn’t tend to maintain this kind of binding very well and you may have to reset every once in a while.

You can contact IKEA and ask them if the two button device is going to be upgraded to Zigbee 3.0. That might help solve the problem. There’s nothing you can do about it from the smartthings side if it’s using an incompatible profile.

I’ll admit, seeing the exact same question in what is now four different threads this morning has physically exhausted me. I can’t keep track of what conversations are happening where. (Remember I have to do everything in my head since I rely on text to speech.) So I’m going to leave this discussion at this point and you can carry-on with other folks.

2 Likes

This is not working with the Dimmer/2 button device. The way how it pairs to the bulb changes the group assignment, I guess. Meanwhile the 5 button remote is capable to pair to the bulb and keep connected to SmartThings. Indeed the Dimmer keeps connected to SmartThings as well as battery reporting still goes through, and that makes me believe that the TouchLink pairing changes the group assignment.

And as @JDRoberts wrote, please stop making multiple threads about the same device/issue. It just makes complicated everything.
Your approach to the issue is like riding a horse sitting backward. You should have tried first how the devices are working before starting to bombard support and the forum with an Armada of topics and emails about a SmartApp what wouldn’t work due to your device set up and the current limitations (I use limitation, but it is really a feature what you are trying to use) of the system.

2 Likes

Also, please give the model number of your button. IKEA has released a number of different handheld remotes over the last two years, and they have different functionality.

Originally, the plug-in pocket socket was sold in a “kit“ with a two button remote. That one could detect pressed or held. It did not send setlevel, so it could not be used for dimming. But because it could distinguish between press and long press, you actually got four functions out of the two button remote.

Then there was a dimmer which you could spin.

And in the last 12 months they have released two new devices. One is a button that does do setlevel, so it can be used for dimming.

And the newest one is a “shortcut“ button.

So which one do you have and which DTH are you using for it?

The way I use this forum is a response to my experiences in using the smartthings.com site.

a) I started with Getting Started, and found it does not get you started.
b) I clicked on Tutorials and found that it leads to either the 2 getting started examples and the Reference material
c) I read the documentation to find out how to develop. I came across behaviour that did not agree with the documentation. I found mistakes in the documentation. I came across inconsistencies which I could not resolve.
d) According to all the information I had available from the SmartApp, the responses from the API, the workspaces and IDE’s I had a working setup (The button was shown with no issues reported, and responded to all API calls referring to it)

I agree I should have checked that the pairing was still valid. In the same way as I should check the oil level in my engine with the dipstick, while the manufacturer’s sensor should be checking it too.

So I’m quick to admit to that omission. Would Smartthings admit that they shouldn’t leave the dead body of a button lying around to fool the developer into thinking it’s been talking to it recently?

And my approach of “bombarding” the support forums, I thought it was just to find someone to respond with actionable details (which you have - thank you), instead of “it’s the future”.

The fact that the same issue arises in multiple threads in the forum? Maybe you should think about a different way to do the documentation?

I was also hoping for some tangible discussion on certain areas too (instead of “we’ll feed that back to the developers”), but it doesn’t look like my approach is particularly welcome. Where do I go to get a refund on my 79 pound Smartthings hub?

This forum was set up many years ago, before the Samsung acquisition, So that customers could help other customers with ideas and projects. It is not an official support channel.

99% of the people posting here are just other customers, and we are all doing the best we can to help each other.

(There are a few staff members who post here from time to time, and we are grateful for their participation, but that’s not really what the forum is for. Their profiles will identify them as staff members.)

With regards to the official materials, warranty support, or refunds, you would need to go through an official support channel

UK:

https://support.smartthings.com/hc/en-gb

US:

https://support.smartthings.com/hc/en-us

You can use the search in the top and you would have a lot of answers. This is a community forum, not an official documentation.

The on/off switch works as a button with SmartThings and you can assigne actions to the press, held functions for each (top/bottom) buttons as well.

And if you would spend 15 pound on the 5 button remote, then you could do what you wanted to do at the first place as that one works like that.