setCapabilityValue not reflected

I’m trying to revive old Broadcom app, 5 years no updates… developer seems to be gone, no forum no email appearance etc… but anyway, trying to improve it and struggle to find reason for setcapabilityValue not working :

await this.setCapabilityValue(‘learnIRcmd’, false).catch(this.error);

no error, it’s being called correctly but simply in the GUI nothing changed


	"type": "boolean",
	"title": {
		"en": "Learn IR command",
		"nl": "Leer IR commando"
	"getable": true,
	"setable": true,
	"insights" : true,
	"uiComponent": "button",
	"insightsTitleTrue": {
        "en": "Learning mode activated",
        "nl": "Leer modus geactiveerd"
    "insightsTitleFalse": {
        "en": "Learning mode deactivated",
        "nl": "Leer modus gedeactiveerd"

Capability does exists, triggering the change via dev. interface reflects the state in the device.

Anyone got any idea, what could be wrong ?

I"s not caching issue, when I recreate the device, it’s still the same.

app.json - relevant part, which is actually created thanks to the homeycompose and relevant sections, looks following :

  "class": "button",
      "capabilities": [
      "mobile": {
        "components": [
            "id": "icon",
            "capabilities": []
            "id": "button",
            "capabilities": [

Thank you.

I think the “mobile” part device json is deprecated. You define the device page in the capability json using uiComponent.
Don’t know if this has any effect in your case.

1 Like

Thank you for your reaction. I believe so, was wondering the same but didn’t found any reference in Upgrading to SDK v3 | Homey Apps SDK - anyway, even after removal, no change in the behavior. ;-( I have tried to switch also button by toggle, the same. :unamused:

The code I’m working on, is related to RM3 Mini - com.broadlink/drivers/RM3_mini at master · shaarkys/com.broadlink · GitHub with com.broadlink/.homeycompose at master · shaarkys/com.broadlink · GitHub (it’s work in progress). From my perspective, everything looks correct but it probably isn’t ;-(



When I added another sensor capability to track “learning mode”, it behaves as it should but the button kept re-enabling the same second it gets pragmatically turned off.

Not really sure what was/is the cause of it, but simply by adding timeout, now it gets reflected as desired.

So basically (simplified case, in real scenario, button is attempted to be disabled after several secs):

not working

async onCapabilityLearnIR(onoff) {  
      await this.setCapabilityValue("learnIRcmd", false).catch(this.error); #button doesn't work
      await this.setCapabilityValue("learningState", false).catch(this.error); #sensor doesn'twork


  async onCapabilityLearnIR(onoff) {

    this.learnTimeout = setTimeout(async () => {
      await this.setCapabilityValue("learnIRcmd", false).catch(this.error); #button works
      await this.setCapabilityValue("learningState", false).catch(this.error); #sensor works
    }, 0); // Delay of 0 seconds

(yep, intentionally tested with 0 seconds…)

Can someone explain this to me (amateur, not developer) ?

Do yo really want to change the capability inside the capability listener?
If you have an onoff capability added as switch (also possible on button page), you can turn on/off via GUI.
The capablity is changed internally to the new value. The lishener you can use to react on the user input to call an API.

1 Like

If I understand you well, user interact in the GUI but I need to switch off the button after either timeout or successful action (in this case IR signal learned) - any of those actions however occurs no later then within few seconds, yet the button always reverted back.

Even I found workaround, I’m not really getting what I did wrong :wink:

My guess is that the SDK does something with the original value after it has called any capability listeners. In other words: it assumes that listeners don’t have any side-effects, like changing the value of the capability to anything other than the original value.

The reason it works with the timeout is because it “lifts” the code from the current running context and schedules it to run at a later point in time (even with a timeout of 0).

1 Like

That’s right. Throwing an error inside the async capability listener cancels the user action and the capability is not changed.
So the capability is changed internally after the listener finishes.

1 Like