Homey.devices.updateDevice in HomeyScript

Trying to update the class of a device, via:

for (const device of Object.values(devices)) {
  if (device.zone != zombieZone.id)
    continue;
  if (device.class == "light") {
    device.virtualClass = "other";
    await Homey.devices.updateDevice({ id: device.id, device });
  }
}

But results in

———————————————————
❌ Script Error
⚠️ TypeError: Cannot read properties of null (reading 'approximation')
    at Function.value (/app/node_modules/athom-api/dist/index.js:1:863528)
    at o.<anonymous> (/app/node_modules/athom-api/dist/index.js:1:847079)
    at x (/app/node_modules/athom-api/dist/index.js:1:346562)
    at u._invoke (/app/node_modules/athom-api/dist/index.js:1:346357)
    at e.<computed> [as next] (/app/node_modules/athom-api/dist/index.js:1:346741)
    at t (/app/node_modules/athom-api/dist/index.js:1:9216)
    at /app/node_modules/athom-api/dist/index.js:1:9312
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

How can I update the device from HomeyScript?

Looks like you can’t:

await Homey.devices.updateDevice({ id : device.id, device : { virtualClass : 'other' } });
...
❌ Script Error
⚠️ Missing Scopes: Missing Scopes
    at /app/node_modules/athom-api/dist/index.js:1:1247257
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

Yeah, I tried the simple object form as well, without success. I’ve been able to update the device via e.g curl -X PUT -H 'Content-Type: application/json' -d '{"class":"other"}' <homey-url>/api/manager/devices/device/<device-id> but I was hoping to do the same thing from HomeyScript.

And I can’t use await fetch('api/manager/devices/device', ...); as only absolute URLs are supported.

I don’t really understand how Athom blocks this operation from HomeyScript but you can still do it from an HTTP request :man_shrugging:t3:

But you can make HTTP requests from HomeyScript using fetch(). Bit of a strange workaround, but if it works, it works.

You can probably use http://127.0.0.1/api/manager/devices/device

2 Likes

Thanks! This worked in the end:

for (const device of Object.values(devices)) {
  if (device.zone != zombieZone.id)
    continue;
  if (device.class == "light") {
    await fetch('http://127.0.0.1/api/manager/devices/device/' + device.id, {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json', 'Authorization' : "Bearer <token>"},
      body: JSON.stringify({ 'class': 'other' })
    });
  }
}

A bit awkward to have to hard-code the authorization :slight_smile:

(For context, I used this to turn a bunch of bulb light devices that I have aggregated into a single light via into class:other, so that Homey doesn’t report them as part of the “15 lights are on” in the latest mobile app update).

updateDevice and deleteDevice can only be used from the Homey Developer Tools.

As about changing the class of a device, you can just do: myDevice.setClass('...');

It means we can actually delete a device from a driver through this API! Good news.

Thanks for the tip about not being able to do updateDevice from HomeyScript, it worked i the developer tools as you say. But setClass doesn’t seem to work: device.setClass is not a function. No problem, I just use the REST endpoint :slight_smile:

Surprising, my app ESPhome does it from the driver on existing device:

                    // Get virtual device
                    let virtualDevice = this.getDevices().filter(virtualDevice => virtualDevice.getData().id === virtualDeviceId)[0];

                    // Modify the class
                    if (virtualDevice.getClass() !== newDeviceClass) {
                        virtualDevice.setClass(newDeviceClass);
                    }

remark:: yes I could use find instead of filter :slight_smile:

Right, the app can do it on its own devices, via the App SDK, but it’s not part of the JS API for the Web API

I have exactly the same issue : change the class of some devices from ‘light’ to ‘heater’.
But, I was not successful using your code !!
Could you give me more detailed process ?
Regards

I try this code, it seems working, but the new class does not remain after the end of the code …
image
And the result :
image

I’ve tried your code, and there is no error , but no result, the class is not modified :


and the result :
image
Could you help me ?
REgards

You have to replace this with your actual bearer token. There are a few ways to do this, not sure which one is the best one: homey get bearer token - Google Search

I understand, now. It is so obvious …
I look for this token, but I was not successful …

I still need some extra help !!

device is not updated dynamically, after you make the call to fetch() you need to reload the script to see if the class has changed (or go to this page).

Finally, I got the bearer token by the mean of Robert Klepp code.
And I was succesful changing the class of devices from light to Heater.
Thanks a lot for your help