Invalid Capability

Hi! I develop app
when setCapabilityOptions with empty object and read it app throw a error
2024-09-16T16:00:00.401Z [err] [ManagerDrivers] [Driver:light] [Device:5b53fe8d-6b85-4d03-ab98-4ad17974cbff] Device.onInit Error: Error: Invalid Capability: dim

here is my code

if (!this.hasCapability(capability)) {
  await this.addCapability(capability);
   await this.setCapabilityOptions(capability, {});
}
const capabilityOptions = this.getCapabilityOptions(capability);

expect get empty object {} in capabilityOptions

So on which call does it fail exactly?

const capabilityOptions = this.getCapabilityOptions(capability);

It could be that adding a new capability in onInit requires that method to end before you can use the capability, or retrieve its options.

So something like this:

async onInit() {
  if (!this.hasCapability(capability)) {
    await this.addCapability(capability);
    await this.setCapabilityOptions(capability, {});
  }
  setTimeout(() => this.onInit2(), 0);
}

async onInit2() {
  const capabilityOptions = this.getCapabilityOptions(capability);
}

@makleso6 Hi Maxim - I suspect you have moved on from this problem; but for the sake of logging my own frustrations and (hopefully solutions), I shall post this here…

I too suffered with this problem. It appears that, as @robertklep suggested capabilities are not fully instantiated for the device until onInit has completed. There is a second method onAdded. When I place getCapabilitiesOptions() in the onAdded() method it works. Clearly there is a lifecycle that devices pass through. Our problem, as developers of Homey apps, is the sparsity (aka complete lack) of information around such important details as what the lifecycle is.

I will continue to experiment with onAdded and report back here.

Device Lifecycle

Elaborating on what I have found so far… The (start of) the lifecycle for a device seems to be:

Driver.onMapDeviceClass - device "quasi-exists" - you can specify which class is the concrete instantiation of the device
Device.onInit - the first time you can programmatically do stuff with the device
Device.onAdded - the device and its capabilities exist "fully"

The usage I am making of these methods is:

onMapDeviceClass

Assign the class that will be the code base for the device. Using this method the same driver can manage different classes of device, for example.

Summary

This text will be hidden

onInit

Add a distinct set of capabilities to each different class of device - in this method it is not possible to change the capability options which you will (probably) want to do. In my app implementation, the capabilities entry in the driver manifest is an empty array - all capabilities are added programmatically.

Summary

This text will be hidden

onAdded

Set the options of the capabilities - most typically changing the titles so that sub-capabilities are distinguished from each other in the Homey UI

My device classes are arranged in an inheritance hierarchy.

  1. homey.device is the base class (obviously)
  2. krakenDevice is an abstract class that extends homey.device
  3. productTariff is one of three concrete device classes that extend krakenDevice

By using onMapDeviceClass I ensure that each device is instantiated by the correct concrete device class. This arrangement seems to work very well.