FlicScript Matter Examples
-
I'm curious about controlling Matter devices via FlicScript. I was able to use getNodes to list my Matter devices, but I'm having a hard time understanding exactly what would need to be passed to the sendCommand method.
Are there any working example scripts on how to control Matter devices?
-
@Emil Neat! I am seeing that setting
MoveToLevel
withOptionsOverride
set to1
does set the brightness when the light is off when it is turned back on via Matter, such as in the Apple Home app (which is something I've never been able to do via any exposed app controls). But, oddly Tapo itself seems to not honor that setting if I turn the light back on via the Tapo app, or more importantly via the wall switch. Seems like a Tapo quirk/bug and not an issue with FlicScript since it seems the setting is properly honored within the Matter protocol.From poking around more, I found the
OnLevel
attribute which looked interesting and I was able to set that withmatterModule.writeAttribute(thisMatterDeviceID, 1, 'Level Control', 'OnLevel', brightnessLevel, () => {})
. This appears to basically do what I want when the light is off, it will always get turned on to the specified brightness level. This has the effect of not keeping a manually set brightness, after the light is turned off and back on it will turn on to the specifiedOnLevel
brightness instead of the previously manually set brightness, but I think that is actually totally fine for my desires in this project.This is so much fun to be able to work with Matter devices at such a low level! I really appreciate your advice and help with this all!
-
@pico You can adjust the brightness even when it is off, so that it will remember the configured brightness the next time it is turned on. Execute the command I wrote under "setting brightness", adjusting node id and level as you wish.
The "options" is a bit map with currently only having one defined bit "ExecuteIfOff": "If this bit is set, commands in this cluster are executed and potentially change the CurrentLevel attribute when the OnOff attribute of the On/Off cluster is FALSE".
So, if you change OptionsOverride to 0 in the command, the command will be discarded in case the light is off. But if you leave it as 1, then the brightness will be modified in case the light is off.
You cannot write to the CurrentLevel attribute directly using a raw write since it is read only. You need to use one of the commands to adjust the level.
-
@Emil About needing the current state on demand rather than listing for updates... I want to write a script to adjust the brightness of lights throughout the day (dimming them hourly throughout the evening). This is also why I asked about sleeping in FlicScript.
I've already done this functionality through IFTTT using their scripting capabilities and jumping through hoops triggering Tapo shortcuts for turning lights back off after a delay if they were off before changing the brightness, but I'm hoping to make it simpler and more efficient through FlicScript.
The catch is that to adjust the brightness you need to turn the light on. So, if the light is already on, I can set the new brightness and that's that. But, if the light is off, it needs to be turned on to the new brightness and then turned back off so that when it's next turned on manually it will be at the desired brightness. To do this properly, I need to know if the light was currently on or off before adjusting the brightness so that it can be back in its previous state after the change is done. It's a little weird to have my lights turn on and off throughout the evening but not being blasted will full brightness lights later into the evening is nice.
It would be amazing if it were possible to adjust the "remembered" brightness without turning the light on, but from what you described before it sounds like that's not possible even with this more direct access to the Matter devices. Or am I mistaken? I haven't had a chance to test that deeply yet. Would
writeAttribute
be able to adjust the brightness without turning a light on? -
@picomitchell wrapping a subscription using await works fine. Just make sure you remember to cancel it when done. The data is cached by the hub so no extra round trip will be necessary to the device. Out of curiosity, what is your use case for that functionality instead of listening to event updates? You can save the latest value in some variable which would be accessible by the rest of the code.
Writing attributes is not that common to do in an automation setup, since most things can be done by sending commands, but often settings that are to be stored for some time are modelled as attributes that you write to.
-
@Emil Thank you so much, this is exactly the info I was hoping for! I've already done a proof of concept and it was so awesome to be able to toggle my Matter light via script, it's gonna be so much fun to control my house this way!
About getting the current status, the only way is via the asynchronous subscription? There is no synchronous way to just directly query the current status? If so, I can build a synchronous function around a subscription that is awaited and then canceled when the value is retrieved. Just want to be sure that is the best option before I move forward with that.
Also, out of curiosity, what would the
writeAttribute
method be used for? -
@picomitchell See the following.
At the top of your file, put
matter = require('matter');
.Turning on and off:
matter.sendCommand("5716184942583194821", 1, "On/Off", "On", {}, (error, response) => console.log(JSON.stringify(error) + ", " + JSON.stringify(response))); // Turn on matter.sendCommand("5716184942583194821", 1, "On/Off", "Off", {}, (error, response) => console.log(JSON.stringify(error) + ", " + JSON.stringify(response))); // Turn off matter.sendCommand("5716184942583194821", 1, "On/Off", "Toggle", {}, (error, response) => console.log(JSON.stringify(error) + ", " + JSON.stringify(response))); // Toggle
The above assumes the node id of the device you are controlling is 5716184942583194821 (which you get from the
getNodes()
function) and the On/Off cluster you want to control is located at endpoint 1. Most devices have all the relevant clusters positioned at endpoint 1, but if one device has several logical parts (like a lamp with multiple light sources), they would typically have one endpoint per light source. Also Matter bridges have many endpoints; each bridged device is exposed as one or multiple endpoints.The third parameter "On/Off" is the name of the cluster and the following parameter is the name of the command (contained within that cluster) that you want to execute. These three commands take no option fields in this case, so the fourth parameter is just an empty object
{}
. The last parameter is a callback, executed when the the remote device has delivered the response, possibly with some return fields.Setting brightness:
matter.sendCommand("5716184942583194821", 1, "Level Control", "MoveToLevel", {"Level": 110, "TransitionTime": 0, "OptionsMask": 1, "OptionsOverride": 1}, (error, response) => console.log(JSON.stringify(error) + ", " + JSON.stringify(response)));
The level you can set is typically in the range 1 (minimum) to 254 (maximum). Set
OptionsOverride
to 0 if you don't want the command to take effect in case the light is off (so that when you later turn it on, it would be at the same level it was before). You can also replace the command name to MoveToLevelWithOnOff to make sure the light turns on when you simply set brightness to something more than 1, in case it was off. The transition time is in the unit 10ths of a second.Setting color using hue/saturation:
matter.sendCommand("5716184942583194821", 1, "Color Control", "MoveToHueAndSaturation", {"Hue": 254, "Saturation": 254, "TransitionTime": 0, "OptionsMask": 1, "OptionsOverride": 1}, (error, response) => console.log(JSON.stringify(error) + ", " + JSON.stringify(response)));
Hue and Saturation fields are both from 0 to 254.
Setting color temperature:
matter.sendCommand("5716184942583194821", 1, "Color Control", "MoveToColorTemperature", {"ColorTemperatureMireds": 370, "TransitionTime": 0, "OptionsMask": 1, "OptionsOverride": 1}, (error, response) => console.log(JSON.stringify(error) + ", " + JSON.stringify(response)));
The color temperature is in "mireds" (https://en.wikipedia.org/wiki/Mired). The Tapo light bulb has a range from 153 (coldest) to 400 mireds (warmest).
You can use the "command" window in the hub sdk to experiment with various commands. I recommend you to also use the Matter Other action in the app to experiment with various options.
To monitor the state, you can use the subscription feature:
let subscription = matter.subscribe("5716184942583194821", [{endpointId: 1}]);
If you want to filter on a specific endpoint/cluster/attribute, you declare that in the options parameter (all those three are optional). It is an array so you can put multiple filter (the updated attribute must match at least one filter). For example,
[{endpointId: 1, clusterName: "Level Control", attributeName: "CurrentLevel"}]
will only match the brightness. For On/Off status, you would want[{endpointId: 1, clusterName: "On/Off", attributeName: "OnOff"}]
. The filter[{}]
will listen to everything (wildcard).You get updates by registering an event listener for the
update
event:subscription.on("update", function(d) { console.log("connected: " + d.connected); if (d.updates === undefined) return; console.log(JSON.stringify(d.updates)); });
Initially you will get an immediately delivered event containing the current status (assuming the device is connected). This is indicated by
d.initialProbe == true
. You will get an update every time the connectivity changes true/false. The attribute updates will contain something like{"1":{"Level Control":{"CurrentLevel":254}}}
where from out to in you have endpoint number, cluster name, attribute name, value. Multiple attributes will be reported at once if they are updated at the same time. To see the whole structure of a Matter device, I recommend you to set up a subscription for the wildcard filter and print the initial probe result to the console.You can call the
cancel()
method on the subscription to stop getting updates (which also releases the resources). -
@Emil Thank you! I would like to control plugs and light switches, both with basic on/off and some with dimming. I also have one color changing bulb I would like to be able to set color temperature and brightness on. But would like to just start with the basics of turning a plug on and off and then move to brightness and then to color.
Also, would like to be able to see the current on/off state of a device, is that possible?
If the specific devices are important, I'm using Tapo stuff:
Basic Plug: https://www.tapo.com/us/product/smart-plug/tapo-p125m/
Dimmable Plug: https://www.tapo.com/us/product/smart-plug/tapo-p135-kit/Basic Switch: https://www.tapo.com/us/product/smart-switch/tapo-s505/
Dimmable Switch: https://www.tapo.com/us/product/smart-switch/tapo-s505d/Multicolor Bulb: https://www.tapo.com/us/product/smart-light-bulb/tapo-l535e/
-
@picomitchell What device type are you trying to control? If you tell me the command you want to send and which parameters, I can give you an example. You can use the Matter Other action in the Flic app to list all the different commands available and options.