athombv / homey-web-api-issues

This issue tracker is for Homey Developers using the Web API.
4 stars 1 forks source link

Issue with calling `makeCapabilityInstance()` multiple times for the same device/capability. #22

Closed robertklep closed 1 year ago

robertklep commented 1 year ago

Background: my HomeKitty app allows devices to be (un-)exposed from HomeKit. When a device is unexposed, I will stop listening to capability changes by destroying a previously created capability instance (using device.makeCapabilityInstance()).

However, when a device is exposed to HomeKit again, it should start listening to capability changes and I create a new capability instance for that. But the listener for that instance is never called when the capability changes.

Code to reproduce (replace the device id with one of your own devices that has an onoff capability):

const Homey = require('homey');
const { HomeyAPIApp } = require('homey-api');

module.exports = class MyApp extends Homey.App {

  async onInit() {
    const api = new HomeyAPIApp({ homey: this.homey });
    await api.devices.connect();
    const device = await api.devices.getDevice({ id : 'ccafde03-6c28-44b8-8ace-78d867c19f48' });
    this.makeCapabilityInstance(device);
  }

  makeCapabilityInstance(device) {
    this.log('making capability instance');
    const instance = device.makeCapabilityInstance('onoff', value => {
      this.log(`device ${ device.name } onoff changed to "${ value }"`);
      this.log(`destroying instance`);
      instance.destroy();
      setTimeout(() => {
        this.makeCapabilityInstance(device);
      }, 2000);
    });
  }
}

This logs:

[log] 2023-01-10 13:18:34 [MyApp] making capability instance
[log] 2023-01-10 13:18:37 [MyApp] device HK Light onoff changed to "true"
[log] 2023-01-10 13:18:37 [MyApp] destroying instance
[log] 2023-01-10 13:18:39 [MyApp] making capability instance

So the first change of onoff calls the listener, then destroys it, then waits 2s (to rule out a timing issue) and creates a new one, but the second listener is never called when I change the capability from the web app.

robertklep commented 1 year ago

If I'm reading the code correctly, it might be caused by the connect/disconnect logic in Item.js:

robertklep commented 1 year ago

A workaround would be to retrieve a new uncached device instance every time:

setTimeout(() => {
  this.makeCapabilityInstance(await this.api.devices.getDevice({ id : 'ccafde03-6c28-44b8-8ace-78d867c19f48', $cache : false }));
}, 2000);

But that seems like a waste of resources.

robertklep commented 1 year ago

Better workaround: when cleaning up the old listeners, I set device.io = null, which confirms my suspicion from my comment about the realtime subscription handling.

jeroenwienk commented 1 year ago

Fixed in https://www.npmjs.com/package/homey-api/v/1.10.8

OlivierZal commented 1 year ago

I confirm this is fixed.

Thanks @jeroenwienk