Skip to content

Instantly share code, notes, and snippets.

@torarnv
Last active January 14, 2024 13:00
Show Gist options
  • Save torarnv/7f1eb93de4d1abe3910839de628b1d05 to your computer and use it in GitHub Desktop.
Save torarnv/7f1eb93de4d1abe3910839de628b1d05 to your computer and use it in GitHub Desktop.
commit e08a61503694907f7ece8f40b6b3ac02e5524256
Author: Tor Arne Vestbø <torarnv@gmail.com>
Date: Tue Aug 29 22:44:45 2023 +0200
Expose updateCapabilityValue endpoint from ManagerDevices
The setCapabilityValue endpoint will end up in the device's
_onSetCapabilityValue callback, triggering its capability
listeners, which in turn results in sending an external
state change to the connected device (via API, RF, etc).
In the cases where we are informing Homey about an external
state change that has already happened, we want to update
Homey's state, run Flows, etc, but not recurse back into
the device's _onSetCapabilityValue, as that would send
out a redundant external state change, potentially
triggering a mode in the external device such as the
typical "choose dim level" behavior.
This is where updateCapabilityValue is useful.
The endpoint has offers the same `value` and
`transactionId` arguments as setCapabilityValue
(although the latter isn't propagated for either
of them), but does not offer `opts`, as that was
not handled by any of the existing plumbing for
updateCapabilityValue.
As the application-side device keeps its own local
state for each capability, we need to emit an
onDeviceUpdateCapabilityValue message to the driver
as well, so that the app is in sync with what Homey
knows.
Note that during setCapabilityValue, which calls
updateCapabilityValue as part of the implementation,
the setCapabilityValue callback comes in first, so
there is no issue with emitting another callback
to the application's driver and devices.
The virtual device driver seems to use its own
dispatching of driver messages, so an additional
entry has been added there too to forward the
onDeviceUpdateCapabilityValue to the device,
via an onUpdateCapabilityValue callback, but
none of the virtual devices seem to keep state
that would necessitate overriding this callback.
Fixes: athombv/homey-web-api-issues#47
diff --git v10.2.1/dist/lib/Device.js patched/dist/lib/Device.js
index 3f4d2c5..fdc9e96 100644
--- v10.2.1/dist/lib/Device.js
+++ patched/dist/lib/Device.js
@@ -956,6 +956,15 @@ module.exports = class Device extends CRUDItem {
originName,
originUri,
}) {
+ // Let the App know
+ await this.sendMessageToDriver({
+ event: 'onDeviceUpdateCapabilityValue',
+ data: {
+ capabilityId,
+ value,
+ },
+ });
+
// Energy
// Calculate Energy Usage
if (ENERGY_CAPABILITIES.includes(capabilityId)) {
diff --git v10.2.1/dist/lib/Driver.js patched/dist/lib/Driver.js
index e68773b..048100d 100644
--- v10.2.1/dist/lib/Driver.js
+++ patched/dist/lib/Driver.js
@@ -220,6 +220,7 @@ module.exports = class Driver extends CRUDItem {
'onDeviceRename',
'onDeviceSettings',
'onDeviceSetCapabilityValue',
+ 'onDeviceUpdateCapabilityValue',
'onPairSessionCreate',
'onPairSessionEvent',
'onPairSessionCallback',
diff --git v10.2.1/dist/lib/ManagerDevices.js patched/dist/lib/ManagerDevices.js
index 6166e09..2bb1ed7 100644
--- v10.2.1/dist/lib/ManagerDevices.js
+++ patched/dist/lib/ManagerDevices.js
@@ -116,6 +116,29 @@ module.exports = class ManagerDevices extends Manager {
});
},
},
+ updateCapabilityValue: {
+ path: '/device/:deviceId/capability/:capabilityId/update',
+ method: HTTP_METHODS.PUT,
+ scopes: [SCOPES.DEVICE_CONTROL],
+ parameters: {
+ value: {
+ in: 'body',
+ required: true,
+ type: [String, Number, Boolean],
+ },
+ transactionId: {
+ in: 'body',
+ type: String,
+ },
+ },
+ async operation({ $session, ...props }) {
+ const origin = HomeyUtil.getOriginObject({ $session });
+ return this.updateCapabilityValue({
+ ...props,
+ ...origin,
+ });
+ },
+ },
};
static CAPABILITY_HELPERS = Object.keys(HomeyLib.getCapabilities()).reduce(
@@ -205,6 +228,30 @@ module.exports = class ManagerDevices extends Manager {
});
}
+ async updateCapabilityValue({
+ deviceId,
+ capabilityId,
+ value,
+ originUserId,
+ originUserName,
+ originClientId,
+ originClientName,
+ originName,
+ originUri,
+ }) {
+ const device = await this.getDevice({ id: deviceId });
+ return device.updateCapabilityValue({
+ capabilityId,
+ value,
+ originUserId,
+ originUserName,
+ originClientId,
+ originClientName,
+ originName,
+ originUri,
+ });
+ }
+
async getCapabilityHelper({ capabilityId }) {
return this.constructor.CAPABILITY_HELPERS[capabilityId] || {};
}
diff --git v10.2.1/dist/lib/VirtualDevice.js patched/dist/lib/VirtualDevice.js
index f1859b6..ba4e8ad 100644
--- v10.2.1/dist/lib/VirtualDevice.js
+++ patched/dist/lib/VirtualDevice.js
@@ -13,6 +13,10 @@ module.exports = class VirtualDevice extends CRUDItem {
// Overload me
}
+ async onUpdateCapabilityValue({ capabilityId, value }) {
+ // Overload me
+ }
+
async onAdded() {
// Overload me
}
diff --git v10.2.1/dist/lib/VirtualDriver.js patched/dist/lib/VirtualDriver.js
index 44c4048..e7fe3f0 100644
--- v10.2.1/dist/lib/VirtualDriver.js
+++ patched/dist/lib/VirtualDriver.js
@@ -178,6 +178,10 @@ module.exports = class VirtualDriver extends CRUDItem {
return virtualDevice.onSetCapabilityValue(data);
}
+ if (event === 'onDeviceUpdateCapabilityValue') {
+ return virtualDevice.onUpdateCapabilityValue(data);
+ }
+
if (event === 'onFlowCardAutocomplete') {
const { onAutocomplete } =
this.constructor.MANIFEST.flow[data.type][data.id].args[data.name];
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment