How to customise the presentation of a capability?

Hi, I’m a consumer attempting to edit the presentation of a Zigbee light switch I’ve bought to better suit my needs - I’m new to Smartthings stuff so apologies if my questions are rudimentary, but I’m hoping someone here can help me out because I’ve hit a bit of a roadblock.

I originally attempted to do this via DTHs but the other day discovered I can no longer access the Groovy IDE and DTHs have been deprecated, so I have now migrated my switch to this Edge driver (successfully).

The actual JSON presentation change is very simple, I just want a few push buttons added under the slider in the detail view which shortcut to preset dimmer levels; I have no issues adding these into the presentation JSON file (I was unable to find the exact original JSON for the stock presentation anywhere online but this apparently unofficial, user-published copy did show on Google and looks fairly faithful so I’m using that as a base), but my confusion is then how to change the driver I linked above to use this presentation file instead of the default, stock one.

What I have tried:

As far as I can tell I can’t just slot in the new presentation to the original capability and see it changed just for my user account:

smartthings capabilities:presentation:update switchLevel 1 --input switch-level-presentation.json

returns a 403 so I assume it’s trying to change it globally, which understandably I’m denied access to do (Question 1: Is my interpretation of this error correct?)

So I’ve resorted to duplicating the entire capability JSON just to associate a custom presentation with it, which I’ve done by running

smartthings capabilities:create -i switch-level.json

where the switch-level.json file was obtained from the documentation site for Smartthings production capabilities at h ttps://developer-preview.smartthings.com/capabilities/switchLevel (I can’t post a 3rd link in my post because of forum rules). Bizarrely though, despite being the official source for the capabilitiy, when I tried creating this with the JSON as-is I got an error that setLevel can only accept one argument and I had to delete the rate parameter for it to work. (Question 2: How can it be that the official capability JSON isn’t accepted as valid in the Smartthings CLI? Is it out of date?)

Anyway I created this new capability, renaming it to switchLevelCustom in the JSON before I ran the command, and I can see from the output it gave me that Smartthings further renamed the capability to give it the ID greenoption21184.switchLevelCustom. Not sure why, but fine. So now I run

smartthings capabilities:presentation:update greenoption21184.switchLevelCustom 1 --input switch-level-presentation.json

using the modified unofficial presentation JSON I referenced towards the top of the post and that works fine.

Now all the references to the capability in the Edge driver are still pointing to switchLevel rather than greenoption21184.switchLevelCustom, so I do a find-replace in all the Lua files in the driver from capabilities.switchLevel to capabilities['greenoption21184.switchLevelCustom'], and change the device profile it’ll use (switch-level.yml) to point to greenoption21184.switchLevelCustom instead too. I install the modified driver using

smartthings edge:drivers:package zigbee-switch -I

and I can see in the Smartthings app that it’s using this new version, but when I try and move the dimmer slider I just get “A network or server error occurred. Try again later.”

So something’s not right. My assumption is the Lua code failed at run-time but I don’t know any detail how.

Question 3: Anyone know to hand what I’ve done wrong?
Question 4: Is there anywhere I can self-serve diagnostics on the error? Somewhere I can access logs?
Question 5: Even better, I don’t suppose there are any resources around that could guide me to an actual debugging experience with the drivers? I’m using VS Code.
Question 6: Am I really choosing the path of least resistance here to simply adding a few buttons to the app? I feel like it should be less work, not sure if I missed a simpler alternative method.

Happy to also provide the exact files I’m using on GitHub if it would help. Information on any of my questions or just on the post generally is much appreciated. Thanks.

Capabilities can be queried through the CLI with smartthings capabilities switchLevel. Use the -h flag to see other options, like json/yml output to file and viewing presentations and translations.

Correct. You can’t change stock capabilities.

There are many cases where the stock capabilities don’t play by the same rules as we do, most notably how they present in the app with history charts and other neat little graphics. I haven’t tried multiple arguments recently, but I remember being unable to get them to work in the past.

Every capability lives within a randomly generated namespace. Yours will forever be greenoption21184.

“A network or server error occurred. Try again later” generally means that the app was toggled in some way to kick off a command, but no event to update an attribute was received within a reasonable amount of time. If the error pops up quickly, it’s often an issue with your capability. If it takes 5 seconds or so, it’s often that the driver isn’t producing an event. It’s hard to tell anything helpful from just that error.

Live logging is in the CLI.

If you’re really just trying to create a couple pushbuttons, I would leave switchLevel alone and just create a new capability for each button (or you can try multiple buttons on one, but we in the community are only just starting to use capabilities with multiple commands/attributes and they don’t always turn out right). Creating your own expanded switchLevel will cause more problems - the default libraries don’t know to use your alternate version and third party integrations like Alexa/Google won’t work with it.

Capability creation is a bit of a pain. The best documentation for how to assemble everything is by looking at the examples in the API documentation. I’d also suggest posting your capability, presentation, and translation files in this thread in code blocks (put ``` on a separate line above and below your code) so others can look for any errors.

1 Like

Hi Phil, thanks for your replies.

Ah perfect, got it.

Who is “we” here? I thought the stock capabilities and the Smartthings CLI were owned by the same group? When I did the smartthings capabilities switchLevel I found my existing one actually did have the rate parameter, so how it got there when the CLI doesn’t like it I don’t know!

Ah thanks hadn’t spotted that! Got it working now.

Cool I’ve given that a go instead now.

Capability:

{
    "id": "greenoption21184.switchLevelPresets",
    "version": 1,
    "status": "proposed",
    "name": "Switch Level Presets",
    "ephemeral": false,
    "attributes": {},
    "commands": {
        "setLevel": {
            "name": "setLevel",
            "arguments": [
                {
                    "name": "level",
                    "optional": false,
                    "schema": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 5
                    }
                }
            ]
        }
    }
}

Presentation:

{
    "dashboard": {
        "states": [],
        "actions": []
    },
    "detailView": [
        {
            "label": "{{i18n.label}} 5",
            "displayType": "pushButton",
            "pushButton": {
                "command": "setLevel",
                "argument": "5",
                "argumentType": "integer"
            }
        },
        {
            "label": "{{i18n.label}} 4",
            "displayType": "pushButton",
            "pushButton": {
                "command": "setLevel",
                "argument": "4",
                "argumentType": "integer"
            }
        },
        {
            "label": "{{i18n.label}} 3",
            "displayType": "pushButton",
            "pushButton": {
                "command": "setLevel",
                "argument": "3",
                "argumentType": "integer"
            }
        },
        {
            "label": "{{i18n.label}} 2",
            "displayType": "pushButton",
            "pushButton": {
                "command": "setLevel",
                "argument": "2",
                "argumentType": "integer"
            }
        },
        {
            "label": "{{i18n.label}} 1",
            "displayType": "pushButton",
            "pushButton": {
                "command": "setLevel",
                "argument": "1",
                "argumentType": "integer"
            }
        }
    ],
    "automation": {
        "conditions": [],
        "actions": []
    },
    "id": "greenoption21184.switchLevelPresets",
    "version": 1
}

(I have no idea what the labels do or what {{i18n.label}} means as they don’t appear visually in the app but the CLI complained when I deleted them and other examples I saw had this string as their label.)

I’ve then edited the Lua driver to handle the capability’s setLevel command. This doesn’t seem to be working either though - only two buttons show up (and they show vertically, is there any way to get them horizontal? And to change the fill colour of them?), and when I click them I get that same “network or server error” message. Nothing appears in the logs when they’re clicked despite the log statement in the handler, so I’m guessing the handler isn’t properly registered, though the code looks ok to me?

We being users creating our own capabilities. There’s another layer - the app plugin - that operates on top of everything you see in the CLI. Some of that special stuff works there. If your second parameter worked, that’s great. Next step is seeing whether you can get it to appear in the automation screens.

Run smartthings capabilities:translations greenoption21184.switchLevelPresets 1 en -j and you’ll see the translation that was auto-generated for your capability:

{
    "tag": "en",
    "label": "Switch Level Presets",
    "attributes": {},
    "commands": {}
}

Translations didn’t used to be required, but things changed a couple weeks ago and now they are. You can build out that structure with entries under attributes and commands to have more labels to use. Query some of the stock capabilities to see what the structure is supposed to look like, and look at their presentations to see how to drill down to different parts of the translation definition. I don’t know that the way you appended a number onto each label will work. I haven’t tried that, but I’m guessing you’ll need to define separate labels in the translation for each.

I also haven’t tried what you’re doing passing an argument with a pushButton, so can’t comment on whether it works. I’m not seeing an example in the stock capabilities where an argument is passed, despite the example in the API docs showing one.

Another way to try this would be to declare 5 different commands in the capability definition, and then map each button in the presentation to a different command. In your driver, you can map all 5 commands to the same handler, and cmd.command will tell you which button was pressed.

I haven’t tried multiple pushButtons on one capability yet. It’s possible that it’s errors in your capability that are preventing the others from showing, or it could be that the app is only allowing two pushButtons right now. I’ve tried 4 states and 3 sliders on a capability though, and all showed up. The app only recently allowed more than one control to display per capability, so the way it shows still could be in flux. If you get the buttons working properly but still only see 2, then you may need to resort to spreading the buttons across multiple capabilities. You could also look into the list presentation type since it’s more compact, though it takes a click to open the list and another to choose the level.

No. Presumably this is will be possible when (if) access is opened up to customize the plugin.

This makes me think the issue is the capability. I’m pretty sure you get something in logs when you fire off a command from the app, even if it’s just a “thread handled” message.

Okay makes sense. I’ve now resorted to just doing two buttons (“up” and “down”), each on a separate (and almost identical) capability with corresponding presentations. I’m finding the Lua code reasonable to work with but capabilities quite a pain. At the moment my issue is that when I click one of the buttons (which are currently coded just to do nothing but log a message saying they were clicked) I get

ERROR Zigbee Switch (Custom)  Candeo light switch thread encountered error: [string "st/driver.lua"]:155: attempt to index a nil value (field '?')

in the logs instead. It seems like it must be an issue in the capability, and I can see that the command name for the button is one thing in the Lua code (by logging the capabilities table), in the capability, in the capability presentation and in the device commands (according to the CLI with smartthings capabilities, smartthings capabilities:presentation, and smartthings devices:commands), but another thing in the device presentation found with

smartthings devices:presentation <deviceNumber> -y

I’m assuming this mismatch is causing the issue. When I try deleting the device from ST and re-adding it the device presentation still carries this alternative command name and I can’t figure out where it’s coming from or how to force it to the right value that the capability’s using. Do you have any ideas how to change it?

What’s the name of the capability you’re currently working with?

Did you already have the capability established, but then changed the name of the command within that capability?

One thing to try, especially if the answer to that second question is yes, is to tweak your profile slightly. The easiest thing to do is to give the main component a label (or change/delete the label if it already has one). That should cause the device presentation to be recreated, pulling in any changes in the underlying presentations. Often what I’ll do on my production drivers is give it a label of ‘Main’, which causes no visible change but still triggers the refresh. Next time I need a refresh, I just delete the label line.

components:
- id: main
  label: Whatever
  capabilities:

Ah thanks I hadn’t realised it was a matter of triggering a refresh of the presentation - the answer to the second question is yes! That turned out to be tricky though, applying the label didn’t work for reconstructing it. What did work in the end though was just using new capabilities under different names. I’ve got it set up and working now - thanks very much for your help! Have a great week.

1 Like

Hello,

I actually am trying to create something similar to the original design that @adamjones posted. The difference is that I want to store the string value I input as the preset value associated with a button. I posted a more detailed question here: Workflow for integrating customized Hub connected device? - #3 by jackj.

@philh30 you mentioned that there is an app-plugin layer. Is that the layer that implements functions like storing recently used color in one button in the “colorControl” capability, because I can’t find implementation detail in capability.presentation JSON file?

Thanks for the help!